mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2026-10-12 08:00:34 +00:00
Compare commits
308
Commits
v1.10.22-lts
..
dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
20b89a8fdd | ||
|
|
8def011e63 | ||
|
|
7c5b2f41e3 | ||
|
|
abd3c24562 | ||
|
|
f4e64ca8b3 | ||
|
|
97fde371d9 | ||
|
|
85bbb9cb15 | ||
|
|
1d34b4aff7 | ||
|
|
dc8c50c07a | ||
|
|
4ac490c6b4 | ||
|
|
0d548c7df9 | ||
|
|
8ec5a5bd4b | ||
|
|
2e8bcc09e6 | ||
|
|
29a304e2c8 | ||
|
|
b1adc37920 | ||
|
|
03fac3ec06 | ||
|
|
6e465ac215 | ||
|
|
21bbadc37b | ||
|
|
3061d640ce | ||
|
|
874717cbcd | ||
|
|
6850acabae | ||
|
|
890ea42749 | ||
|
|
6aaf61cde4 | ||
|
|
73930c5e29 | ||
|
|
8f8d280e90 | ||
|
|
b46192024f | ||
|
|
8f939ad5be | ||
|
|
a6363ce4e5 | ||
|
|
fd490b2642 | ||
|
|
7624670ee0 | ||
|
|
8c3145e1c6 | ||
|
|
bec7b6989f | ||
|
|
326f2654e6 | ||
|
|
708499a335 | ||
|
|
bdeb842939 | ||
|
|
edefdce3ff | ||
|
|
b348c36571 | ||
|
|
6ae150b64e | ||
|
|
3687b9bea2 | ||
|
|
711431da82 | ||
|
|
e93afc33aa | ||
|
|
82dd993751 | ||
|
|
9ba293e154 | ||
|
|
8fa9f128d8 | ||
|
|
ed9f1599e6 | ||
|
|
787a29769d | ||
|
|
6b379389d3 | ||
|
|
5bcbf32823 | ||
|
|
0aa90e1b2d | ||
|
|
a7b87211b4 | ||
|
|
2c666933a5 | ||
|
|
f280b533c6 | ||
|
|
47a16bc9a9 | ||
|
|
713202b6eb | ||
|
|
79020abb1c | ||
|
|
83ef41cf1a | ||
|
|
91675c69e9 | ||
|
|
0e68065b40 | ||
|
|
600b769083 | ||
|
|
e7670f96de | ||
|
|
342c04b30a | ||
|
|
5ab8377ac1 | ||
|
|
74eb2c8dd6 | ||
|
|
f136d97941 | ||
|
|
a5629e3f42 | ||
|
|
515d6ca500 | ||
|
|
c0ccc0318d | ||
|
|
8196c11010 | ||
|
|
170bd22062 | ||
|
|
097a33c68f | ||
|
|
3be3bf9926 | ||
|
|
038f2b4f54 | ||
|
|
f84e284c20 | ||
|
|
48e75b5916 | ||
|
|
a12ceaee6e | ||
|
|
9050680115 | ||
|
|
0022a9b508 | ||
|
|
3437d62f31 | ||
|
|
dc880835d0 | ||
|
|
1663bf8677 | ||
|
|
aed236cbc9 | ||
|
|
90be74504e | ||
|
|
bba8aab18c | ||
|
|
47d135ecca | ||
|
|
d96fe49993 | ||
|
|
ac396b61ce | ||
|
|
6798d0c7ee | ||
|
|
1490ed7541 | ||
|
|
48b3032de6 | ||
|
|
ed12bec460 | ||
|
|
3c4a1ea614 | ||
|
|
79eb0288b4 | ||
|
|
99775e1eb4 | ||
|
|
db848b41d2 | ||
|
|
b5b11dff86 | ||
|
|
9cf4bfc606 | ||
|
|
221162d44f | ||
|
|
617970a1f8 | ||
|
|
5610c73d67 | ||
|
|
51fe02661f | ||
|
|
8f491b2933 | ||
|
|
b7e16bd6d5 | ||
|
|
38ca2ddd01 | ||
|
|
402b41100b | ||
|
|
766beae4e1 | ||
|
|
05f72e9dcf | ||
|
|
23553c68ae | ||
|
|
4dd1eb7a1e | ||
|
|
db307732c6 | ||
|
|
33d4ade1d4 | ||
|
|
186075ff9a | ||
|
|
34df745d1c | ||
|
|
ec363ac157 | ||
|
|
193b0f3cd4 | ||
|
|
67c1bf2924 | ||
|
|
b1373ff77e | ||
|
|
55d0e27212 | ||
|
|
1c052b7c13 | ||
|
|
6c8d48c2dc | ||
|
|
b61dae638b | ||
|
|
872a93aa07 | ||
|
|
b1f337020c | ||
|
|
56858dd74c | ||
|
|
358415f737 | ||
|
|
5e73260103 | ||
|
|
e169f46784 | ||
|
|
39416abd47 | ||
|
|
640a0ca815 | ||
|
|
8e54cd5162 | ||
|
|
0f0099accb | ||
|
|
718ebeb203 | ||
|
|
4101bf691d | ||
|
|
a97deb3dca | ||
|
|
10203d5c0c | ||
|
|
a357d6697d | ||
|
|
555b0aa999 | ||
|
|
6dd0dbe2c3 | ||
|
|
c31bbae768 | ||
|
|
2bb0f15973 | ||
|
|
be229551e3 | ||
|
|
6283eb4c69 | ||
|
|
c329fb6599 | ||
|
|
c3685f6b74 | ||
|
|
f4f5a36475 | ||
|
|
ea1261b48e | ||
|
|
0c68f16a66 | ||
|
|
33e5c9230f | ||
|
|
96eefab36f | ||
|
|
b0b6bf458f | ||
|
|
f3d85d1309 | ||
|
|
39385ea0a0 | ||
|
|
e492c6573c | ||
|
|
10a7fb3be2 | ||
|
|
8bc7cfade3 | ||
|
|
ea044d6c32 | ||
|
|
f6ee3dc75b | ||
|
|
367a74503f | ||
|
|
53b1a7af4c | ||
|
|
078d7fbe1e | ||
|
|
c709e48ceb | ||
|
|
0741f60896 | ||
|
|
af8eef4a91 | ||
|
|
f233ef7069 | ||
|
|
1c199bd3d7 | ||
|
|
036c973fec | ||
|
|
8bb225d272 | ||
|
|
ab932ae154 | ||
|
|
89f969ec6e | ||
|
|
afa8cf22b1 | ||
|
|
67aa8471dc | ||
|
|
0617b81b3b | ||
|
|
98c535a12c | ||
|
|
ec46518936 | ||
|
|
a7b034387f | ||
|
|
7905dd00a6 | ||
|
|
74583aa1aa | ||
|
|
4be9d71edf | ||
|
|
57bfc38eb8 | ||
|
|
aaaa5980b5 | ||
|
|
4f57dfc76e | ||
|
|
2c31ffc66b | ||
|
|
b104a13b71 | ||
|
|
28633d2fef | ||
|
|
9052386c83 | ||
|
|
7bc45f2d77 | ||
|
|
2ef6ecb951 | ||
|
|
ca0dc71338 | ||
|
|
04a1ec9a9a | ||
|
|
999e5a779a | ||
|
|
99f62b7230 | ||
|
|
4dee4e1cc2 | ||
|
|
539addc656 | ||
|
|
1a35b307fa | ||
|
|
a04f4a8b96 | ||
|
|
6b88e1adf2 | ||
|
|
99bc8177d4 | ||
|
|
cf2a1372f2 | ||
|
|
42c30f324a | ||
|
|
dab83fee20 | ||
|
|
6f3c5586fc | ||
|
|
aab8df6abc | ||
|
|
b9be79b05a | ||
|
|
ec3024f2c3 | ||
|
|
070f61e229 | ||
|
|
a82a4ebfc5 | ||
|
|
87009ddb27 | ||
|
|
3650ff27b3 | ||
|
|
6c08a3114a | ||
|
|
381cb61185 | ||
|
|
8d69da7702 | ||
|
|
8922395fdc | ||
|
|
83db40e261 | ||
|
|
95ec6c62ef | ||
|
|
56fc9ea428 | ||
|
|
88c6fc050b | ||
|
|
2392f91567 | ||
|
|
5f0c740eb0 | ||
|
|
120d0dd7c6 | ||
|
|
2844f6db7f | ||
|
|
570074f92d | ||
|
|
a13047c855 | ||
|
|
ca0d24bf56 | ||
|
|
2b18251360 | ||
|
|
f7c875acda | ||
|
|
a291a50c9f | ||
|
|
5bc7bc6aac | ||
|
|
9c376300ff | ||
|
|
5187b20252 | ||
|
|
fc401ffd8f | ||
|
|
667ee5256e | ||
|
|
f8356de93c | ||
|
|
55bb997d51 | ||
|
|
7c46f54e15 | ||
|
|
6dbb6d2247 | ||
|
|
9d0ae45edc | ||
|
|
b467dfa3b2 | ||
|
|
c13387bc70 | ||
|
|
41b2523750 | ||
|
|
afe82bd4be | ||
|
|
0f296fb70b | ||
|
|
d96ccd06a3 | ||
|
|
14095affa9 | ||
|
|
ed60565bc9 | ||
|
|
8313912c4f | ||
|
|
6274015d06 | ||
|
|
d195ce9155 | ||
|
|
cd0cd8a152 | ||
|
|
1f45ed6b06 | ||
|
|
7f6ad89edf | ||
|
|
5cdea288e2 | ||
|
|
e56feaf826 | ||
|
|
1288a09647 | ||
|
|
0cdaafa1c0 | ||
|
|
0b3334253c | ||
|
|
10f72f12d2 | ||
|
|
01643b2816 | ||
|
|
56e0da4fe3 | ||
|
|
144c397bf4 | ||
|
|
e06541984f | ||
|
|
ea7e92db84 | ||
|
|
8d48640c1d | ||
|
|
cfe5cb4b6b | ||
|
|
05c4d7dd38 | ||
|
|
13c6e0df99 | ||
|
|
dafd6ba71e | ||
|
|
2751c37716 | ||
|
|
50c01762e7 | ||
|
|
a77ebd3eb6 | ||
|
|
d84f0b5597 | ||
|
|
a3cdf87ea2 | ||
|
|
8ab3c16b3d | ||
|
|
18e943fd06 | ||
|
|
3b7a067dda | ||
|
|
4636ba815b | ||
|
|
317fad2a28 | ||
|
|
0ae28a1dd9 | ||
|
|
bbfe5f1d96 | ||
|
|
b713f20b66 | ||
|
|
3eb7a5adc5 | ||
|
|
956af78749 | ||
|
|
69ad01687e | ||
|
|
e83d07e88e | ||
|
|
6683696032 | ||
|
|
3396a5ffea | ||
|
|
18a14d3b75 | ||
|
|
2b13352004 | ||
|
|
94e5d7e642 | ||
|
|
001b4dbada | ||
|
|
1192dec689 | ||
|
|
956d47f9da | ||
|
|
063a071228 | ||
|
|
c54a7de827 | ||
|
|
0410e48aad | ||
|
|
a4d95737d3 | ||
|
|
bc64d83ab2 | ||
|
|
87616e388b | ||
|
|
3f35f90fc2 | ||
|
|
c3ba69814c | ||
|
|
66a517e58d | ||
|
|
3108c927af | ||
|
|
5738cceac9 | ||
|
|
db2f648bce | ||
|
|
6012a6cf9f | ||
|
|
a4dcbc90e6 | ||
|
|
955ecce952 | ||
|
|
91fba21ed3 | ||
|
|
490e2934b8 | ||
|
|
cb6d3d4fc3 |
@@ -12,7 +12,7 @@ jobs:
|
|||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: '20.2'
|
node-version: '22.19.0'
|
||||||
- name: Build Web
|
- name: Build Web
|
||||||
run: |
|
run: |
|
||||||
cd frontend && npm install && npm run build:pro
|
cd frontend && npm install && npm run build:pro
|
||||||
@@ -21,7 +21,7 @@ jobs:
|
|||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: '1.23'
|
go-version: '1.24'
|
||||||
- name: Build Release
|
- name: Build Release
|
||||||
uses: goreleaser/goreleaser-action@v6
|
uses: goreleaser/goreleaser-action@v6
|
||||||
with:
|
with:
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ jobs:
|
|||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: '20.2'
|
node-version: '22.19.0'
|
||||||
- name: Build Web
|
- name: Build Web
|
||||||
run: |
|
run: |
|
||||||
cd frontend && npm install && npm run build:pro
|
cd frontend && npm install && npm run build:pro
|
||||||
@@ -21,7 +21,7 @@ jobs:
|
|||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: '1.23'
|
go-version: '1.24'
|
||||||
- name: Build Release
|
- name: Build Release
|
||||||
uses: goreleaser/goreleaser-action@v6
|
uses: goreleaser/goreleaser-action@v6
|
||||||
with:
|
with:
|
||||||
|
|||||||
+6
-4
@@ -10,7 +10,7 @@ before:
|
|||||||
- ./ci/script.sh
|
- ./ci/script.sh
|
||||||
- sed -i 's@ORIGINAL_VERSION=.*@ORIGINAL_VERSION=v{{ .Version }}@g' 1pctl
|
- sed -i 's@ORIGINAL_VERSION=.*@ORIGINAL_VERSION=v{{ .Version }}@g' 1pctl
|
||||||
- go mod tidy
|
- go mod tidy
|
||||||
|
|
||||||
builds:
|
builds:
|
||||||
- main: ./cmd/server/main.go
|
- main: ./cmd/server/main.go
|
||||||
binary: 1panel
|
binary: 1panel
|
||||||
@@ -31,17 +31,19 @@ builds:
|
|||||||
- arm
|
- arm
|
||||||
- ppc64le
|
- ppc64le
|
||||||
- s390x
|
- s390x
|
||||||
|
- riscv64
|
||||||
|
|
||||||
archives:
|
archives:
|
||||||
- format: tar.gz
|
- formats: [ 'tar.gz' ]
|
||||||
name_template: "1panel-v{{ .Version }}-{{ .Os }}-{{ .Arch }}{{- if .Arm }}v{{ .Arm }}{{ end }}"
|
name_template: "1panel-v{{ .Version }}-{{ .Os }}-{{ .Arch }}{{- if .Arm }}v{{ .Arm }}{{ end }}"
|
||||||
wrap_in_directory: true
|
wrap_in_directory: true
|
||||||
files:
|
files:
|
||||||
- 1pctl
|
- 1pctl
|
||||||
- 1panel.service
|
|
||||||
- install.sh
|
- install.sh
|
||||||
- GeoIP.mmdb
|
- 1panel.service
|
||||||
|
- initscript/*
|
||||||
- lang/*
|
- lang/*
|
||||||
|
- GeoIP.mmdb
|
||||||
|
|
||||||
checksum:
|
checksum:
|
||||||
name_template: 'checksums.txt'
|
name_template: 'checksums.txt'
|
||||||
|
|||||||
+1
-1
@@ -10,7 +10,7 @@ PR are always welcome, even if they only contain small fixes like typos or a few
|
|||||||
|
|
||||||
Please submit a PR broken down into small changes bit by bit. A PR consisting of a lot of features and code changes may be hard to review. It is recommended to submit PRs in an incremental fashion.
|
Please submit a PR broken down into small changes bit by bit. A PR consisting of a lot of features and code changes may be hard to review. It is recommended to submit PRs in an incremental fashion.
|
||||||
|
|
||||||
This [development guideline](https://1panel.cn/docs/dev_manual/dev_manual/) contains information about repository structure, how to set up development environment, how to run it, and more.
|
This [development guideline](https://docs.1panel.pro/dev_manual/dev_manual/) contains information about repository structure, how to set up development environment, how to run it, and more.
|
||||||
|
|
||||||
Note: If you split your pull request to small changes, please make sure any of the changes goes to master will not break anything. Otherwise, it can not be merged until this feature complete.
|
Note: If you split your pull request to small changes, please make sure any of the changes goes to master will not break anything. Otherwise, it can not be merged until this feature complete.
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ build_frontend:
|
|||||||
|
|
||||||
build_backend_on_linux:
|
build_backend_on_linux:
|
||||||
cd $(SERVER_PATH) \
|
cd $(SERVER_PATH) \
|
||||||
&& GOOS=$(GOOS) GOARCH=$(GOARCH) $(GOBUILD) -trimpath -ldflags '-s -w' -o $(BUILD_PATH)/$(APP_NAME) $(MAIN)
|
&& CGO_ENABLED=0 GOOS=$(GOOS) GOARCH=$(GOARCH) $(GOBUILD) -trimpath -ldflags '-s -w' -o $(BUILD_PATH)/$(APP_NAME) $(MAIN)
|
||||||
|
|
||||||
build_backend_on_darwin:
|
build_backend_on_darwin:
|
||||||
cd $(SERVER_PATH) \
|
cd $(SERVER_PATH) \
|
||||||
@@ -31,4 +31,4 @@ build_backend_on_darwin:
|
|||||||
|
|
||||||
build_all: build_frontend build_backend_on_linux
|
build_all: build_frontend build_backend_on_linux
|
||||||
|
|
||||||
build_on_local: clean_assets build_frontend build_backend_on_darwin upx_bin
|
build_on_local: clean_assets build_frontend build_backend_on_darwin
|
||||||
|
|||||||
@@ -1,70 +1,87 @@
|
|||||||
<p align="center"><a href="https://1panel.cn"><img src="http://1panel.oss-cn-hangzhou.aliyuncs.com/img/1panel-logo.png" alt="1Panel" width="300" /></a></p>
|
<p align="center"><a href="https://1panel.pro"><img src="https://resource.1panel.pro/img/1panel-logo.png" alt="1Panel" width="300" /></a></p>
|
||||||
<p align="center"><b>Top-Rated Web-based Linux Server Management Tool</b></p>
|
<p align="center"><b>Simplify Linux Server Management</b></p>
|
||||||
<p align="center"><b>现代化、开源的 Linux 服务器运维管理面板</b></p>
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://trendshift.io/repositories/2462" target="_blank"><img src="https://trendshift.io/api/badge/repositories/2462" alt="1Panel-dev%2F1Panel | Trendshift" style="width: 180px; height: auto;" /></a>
|
<a href="https://trendshift.io/repositories/2462" target="_blank"><img src="https://trendshift.io/api/badge/repositories/2462" alt="1Panel-dev%2F1Panel | Trendshift" style="width: 240px; height: auto;" /></a>
|
||||||
<a href="https://hellogithub.com/repository/71791baf930149ac9b84e1acf186573f" target="_blank"><img src="https://api.hellogithub.com/v1/widgets/recommend.svg?rid=71791baf930149ac9b84e1acf186573f&claim_uid=p8vB3kP5CMrthiL&theme=dark&theme=neutral" alt="Featured|HelloGitHub" style="width: 180px; height: auto;" /></a>
|
|
||||||
<a href="https://market.aliyun.com/products/53690006/cmjj00062740.html?userCode=kmemb8jp" target="_blank"><img src="https://img.alicdn.com/imgextra/i2/O1CN01H5JIwY1rZ0OobDjnJ_!!6000000005644-2-tps-1000-216.png" alt="1Panel-dev%2F1Panel | Aliyun" style="width: 180px; height: auto;" /></a>
|
|
||||||
</p>
|
</p>
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://www.gnu.org/licenses/gpl-3.0.html"><img src="https://shields.io/github/license/1Panel-dev/1Panel?color=%231890FF" alt="License: GPL v3"></a>
|
<a href="https://www.gnu.org/licenses/gpl-3.0.html"><img src="https://shields.io/github/license/1Panel-dev/1Panel?color=%231890FF" alt="License: GPL v3"></a>
|
||||||
<a href="https://app.codacy.com/gh/1Panel-dev/1Panel?utm_source=github.com&utm_medium=referral&utm_content=1Panel-dev/1Panel&utm_campaign=Badge_Grade_Dashboard"><img src="https://app.codacy.com/project/badge/Grade/da67574fd82b473992781d1386b937ef" alt="Codacy"></a>
|
<a href="https://app.codacy.com/gh/1Panel-dev/1Panel?utm_source=github.com&utm_medium=referral&utm_content=1Panel-dev/1Panel&utm_campaign=Badge_Grade_Dashboard"><img src="https://app.codacy.com/project/badge/Grade/da67574fd82b473992781d1386b937ef" alt="Codacy"></a>
|
||||||
|
<a href="https://discord.gg/bUpUqWqdRr" target="_blank">
|
||||||
|
<img src="https://img.shields.io/discord/1318846410149335080?logo=discord&labelColor=%20%235462eb&logoColor=%20%23f5f5f5&color=%20%235462eb"
|
||||||
|
alt="chat on Discord"></a>
|
||||||
<a href="https://github.com/1Panel-dev/1Panel/releases"><img src="https://img.shields.io/github/v/release/1Panel-dev/1Panel" alt="GitHub release"></a>
|
<a href="https://github.com/1Panel-dev/1Panel/releases"><img src="https://img.shields.io/github/v/release/1Panel-dev/1Panel" alt="GitHub release"></a>
|
||||||
<a href="https://github.com/1Panel-dev/1Panel"><img src="https://img.shields.io/github/stars/1Panel-dev/1Panel?color=%231890FF&style=flat-square" alt="GitHub Stars"></a>
|
<a href="https://github.com/1Panel-dev/1Panel"><img src="https://img.shields.io/github/stars/1Panel-dev/1Panel?color=%231890FF&style=flat-square" alt="Stars"></a><br>
|
||||||
<a href="https://gitee.com/fit2cloud-feizhiyun/1Panel"><img src="https://gitee.com/fit2cloud-feizhiyun/1Panel/badge/star.svg?theme=gvp" alt="Gitee Stars"></a><br>
|
</p>
|
||||||
[<a href="docs/README_EN.md">English</a>] | [<a href="docs/README_TW.md">中文(繁體)</a>] | [<a href="docs/README_JP.md">日本語</a>]
|
<p align="center">
|
||||||
|
<a href="/README.md"><img alt="English" src="https://img.shields.io/badge/English-d9d9d9"></a>
|
||||||
|
<a href="/docs/README.zh-Hans.md"><img alt="中文(简体)" src="https://img.shields.io/badge/中文(简体)-d9d9d9"></a>
|
||||||
|
<a href="/docs/README.ja.md"><img alt="日本語" src="https://img.shields.io/badge/日本語-d9d9d9"></a>
|
||||||
|
<a href="/docs/README.pt-br.md"><img alt="Português (Brasil)" src="https://img.shields.io/badge/Português (Brasil)-d9d9d9"></a>
|
||||||
|
<a href="/docs/README.ar.md"><img alt="العربية" src="https://img.shields.io/badge/العربية-d9d9d9"></a>
|
||||||
|
<a href="/docs/README.de.md"><img alt="Deutsch" src="https://img.shields.io/badge/Deutsch-d9d9d9"></a>
|
||||||
|
<a href="/docs/README.es.md"><img alt="Español" src="https://img.shields.io/badge/Español-d9d9d9"></a><br>
|
||||||
|
<a href="/docs/README.fr.md"><img alt="français" src="https://img.shields.io/badge/français-d9d9d9"></a>
|
||||||
|
<a href="/docs/README.ko.md"><img alt="한국어" src="https://img.shields.io/badge/한국어-d9d9d9"></a>
|
||||||
|
<a href="/docs/README.id.md"><img alt="Bahasa Indonesia" src="https://img.shields.io/badge/Bahasa Indonesia-d9d9d9"></a>
|
||||||
|
<a href="/docs/README.zh-Hant.md"><img alt="中文(繁體)" src="https://img.shields.io/badge/中文(繁體)-d9d9d9"></a>
|
||||||
|
<a href="/docs/README.tr.md"><img alt="Türkçe" src="https://img.shields.io/badge/Türkçe-d9d9d9"></a>
|
||||||
|
<a href="/docs/README.ru.md"><img alt="Русский" src="https://img.shields.io/badge/%D0%A0%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9-d9d9d9"></a>
|
||||||
|
<a href="/docs/README.ms.md"><img alt="Bahasa Melayu" src="https://img.shields.io/badge/Bahasa Melayu-d9d9d9"></a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
[](https://www.bilibili.com/video/BV1Mt421n7LZ/)
|
|
||||||
|
|
||||||
------------------------------
|
------------------------------
|
||||||
## 什么是 1Panel?
|
|
||||||
|
|
||||||
1Panel 是新一代的 Linux 服务器运维管理面板。
|
1Panel provides an intuitive web interface and MCP Server to manage websites, files, containers, databases, and LLMs on a Linux server.
|
||||||
|
|
||||||
- **高效管理**:用户可以通过 Web 界面轻松管理 Linux 服务器,如主机监控、文件管理、数据库管理、容器管理等;
|
- **Efficient Management**: Through a user-friendly web graphical interface, 1Panel enables users to effortlessly manage their Linux servers. Key features include host monitoring, file management, database administration, container management, LLMs management.
|
||||||
- **快速建站**:深度集成开源建站软件 WordPress 和 [Halo](https://github.com/halo-dev/halo/),域名绑定、SSL 证书配置等操作一键搞定;
|
- **Rapid Website Deployment**: With deep integration of the popular open-source website building software WordPress, 1Panel streamlines the process of domain binding and SSL certificate configuration, all achievable with just one click.
|
||||||
- **应用商店**:精选上架各类高质量的开源工具和应用软件,协助用户轻松安装并升级;
|
- **Application Store**: 1Panel curates a wide range of high-quality open-source tools and applications, facilitating easy installation and updates for its users.
|
||||||
- **安全可靠**:基于容器管理并部署应用,实现最小的漏洞暴露面,同时提供病毒防护、防火墙和日志审计等功能;
|
- **Security and Reliability**: By leveraging containerization and secure application deployment practices, 1Panel minimizes vulnerability exposure. It further enhances security through integrated firewall management and log auditing capabilities.
|
||||||
- **一键备份**:支持一键备份和恢复,用户可以将数据备份到各类云端存储介质,永不丢失。
|
- **One-Click Backup & Restore**: Data protection is made simple with 1Panel's one-click backup and restore functionality, supporting various cloud storage solutions to ensure data integrity and availability.
|
||||||
|
- **MCP Server**: [1Panel MCP Server](https://github.com/1Panel-dev/mcp-1panel) allow user to execute server operations via natural language.
|
||||||
|
|
||||||
## 快速开始
|
## Quick Start
|
||||||
|
|
||||||
**一键安装**
|
Execute the script below and follow the prompts to install 1Panel:
|
||||||
|
|
||||||
执行如下命令一键安装 1Panel:
|
```bash
|
||||||
|
curl -sSL https://resource.1panel.pro/quick_start.sh -o quick_start.sh && bash quick_start.sh
|
||||||
```sh
|
|
||||||
curl -sSL https://resource.fit2cloud.com/1panel/package/quick_start.sh -o quick_start.sh && sudo bash quick_start.sh
|
|
||||||
```
|
```
|
||||||
|
|
||||||
如果是用于离线环境,推荐使用 [安装包方式](https://1panel.cn/docs/installation/package_installation/) 进行安装部署。
|
Please refer to our [documentation](https://docs.1panel.pro/quick_start/) for more details.
|
||||||
|
|
||||||
**学习资料**
|
中国用户请使用此 [安装脚本](https://1panel.cn/docs/v2/installation/online_installation/),默认安装 V2 版本,应用数量相较国际版本更丰富。
|
||||||
|
|
||||||
- [在线文档](https://1panel.cn/docs/)
|
## Screenshot
|
||||||
- [社区论坛](https://bbs.fit2cloud.com/c/1p/7)
|
|
||||||
- [如何加入微信交流群?](https://bbs.fit2cloud.com/t/topic/2147)
|
|
||||||
|
|
||||||
## 专业版
|

|
||||||
|
|
||||||
相比于社区版,1Panel 专业版为用户提供了大量增强功能及技术支持服务,增强功能包括 WAF 增强、网站防篡改、网站监控、GPU 监控、黑金主题及自定义界面等。 [点击查看专业版详细介绍](https://www.lxware.cn/1panel)。
|
## Star History
|
||||||
|
|
||||||
## 飞致云的其他明星项目
|
[](https://star-history.com/#1Panel-dev/1Panel&Date)
|
||||||
|
|
||||||
- [MaxKB](https://github.com/1Panel-dev/MaxKB/) - 基于 LLM 大语言模型的开源知识库问答系统
|
## Pro Edition
|
||||||
- [JumpServer](https://github.com/jumpserver/jumpserver/) - 广受欢迎的开源堡垒机
|
|
||||||
- [Halo](https://github.com/halo-dev/halo/) - 强大易用的开源建站工具
|
Compared to the OSS Edition, 1Panel Pro Edition provides users with a wealth of enhanced features and technical support services. Enhanced features include WAF enhancement, Website monitoring, Mobile APP, custom logo and theme, etc.
|
||||||
- [DataEase](https://github.com/dataease/dataease/) - 人人可用的开源数据可视化分析工具
|
|
||||||
- [MeterSphere](https://github.com/metersphere/metersphere/) - 开源持续测试工具
|
[Click to see Pro Edition details](https://1panel.pro/pricing).
|
||||||
- [KubePi](https://github.com/1Panel-dev/KubePi/) - 现代化、开源的 K8s 面板
|
|
||||||
|
## Security Information
|
||||||
|
|
||||||
|
If you discover any security issues, please refer to [SECURITY.md](/SECURITY.md).
|
||||||
|
|
||||||
|
## GitAds Sponsored
|
||||||
|
|
||||||
|
[](https://gitads.dev/v1/ad-track?source=1panel-dev/1panel@github)
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
Copyright (c) 2014-2024 [FIT2CLOUD 飞致云](https://fit2cloud.com/), All rights reserved.
|
|
||||||
|
|
||||||
Licensed under The GNU General Public License version 3 (GPLv3) (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
|
Licensed under The GNU General Public License version 3 (GPLv3) (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
|
||||||
|
|
||||||
<https://www.gnu.org/licenses/gpl-3.0.html>
|
<https://www.gnu.org/licenses/gpl-3.0.html>
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
|
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
<!-- GitAds-Verify: 9M8AMBB11GYJ3RUNXGB5R1MR71KPATU9 -->
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,257 @@
|
|||||||
|
package v1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/utils/ai_tools/gpu"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/utils/ai_tools/gpu/common"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/utils/ai_tools/xpu"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
// @Tags AI
|
||||||
|
// @Summary Create Ollama model
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body dto.OllamaModelName true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Security Timestamp
|
||||||
|
// @Router /ai/ollama/model [post]
|
||||||
|
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"添加 Ollama 模型 [name]","formatEN":"add Ollama model [name]"}
|
||||||
|
func (b *BaseApi) CreateOllamaModel(c *gin.Context) {
|
||||||
|
var req dto.OllamaModelName
|
||||||
|
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := AIToolService.Create(req.Name); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags AI
|
||||||
|
// @Summary Rereate Ollama model
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body dto.OllamaModelName true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Security Timestamp
|
||||||
|
// @Router /ai/ollama/model/recreate [post]
|
||||||
|
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"添加 Ollama 模型重试 [name]","formatEN":"re-add Ollama model [name]"}
|
||||||
|
func (b *BaseApi) RecreateOllamaModel(c *gin.Context) {
|
||||||
|
var req dto.OllamaModelName
|
||||||
|
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := AIToolService.Recreate(req.Name); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags AI
|
||||||
|
// @Summary Close Ollama model conn
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body dto.OllamaModelName true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Security Timestamp
|
||||||
|
// @Router /ai/ollama/model/close [post]
|
||||||
|
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"关闭 Ollama 模型连接 [name]","formatEN":"close conn for Ollama model [name]"}
|
||||||
|
func (b *BaseApi) CloseOllamaModel(c *gin.Context) {
|
||||||
|
var req dto.OllamaModelName
|
||||||
|
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := AIToolService.Close(req.Name); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags AI
|
||||||
|
// @Summary Sync Ollama model list
|
||||||
|
// @Success 200 {array} dto.OllamaModelDropList
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Security Timestamp
|
||||||
|
// @Router /ai/ollama/model/sync [post]
|
||||||
|
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"同步 Ollama 模型列表","formatEN":"sync Ollama model list"}
|
||||||
|
func (b *BaseApi) SyncOllamaModel(c *gin.Context) {
|
||||||
|
list, err := AIToolService.Sync()
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, list)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags AI
|
||||||
|
// @Summary Page Ollama models
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body dto.SearchWithPage true "request"
|
||||||
|
// @Success 200 {object} dto.PageResult
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Security Timestamp
|
||||||
|
// @Router /ai/ollama/model/search [post]
|
||||||
|
func (b *BaseApi) SearchOllamaModel(c *gin.Context) {
|
||||||
|
var req dto.SearchWithPage
|
||||||
|
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
total, list, err := AIToolService.Search(req)
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
helper.SuccessWithData(c, dto.PageResult{
|
||||||
|
Items: list,
|
||||||
|
Total: total,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags AI
|
||||||
|
// @Summary Page Ollama models
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body dto.OllamaModelName true "request"
|
||||||
|
// @Success 200 {string} details
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Security Timestamp
|
||||||
|
// @Router /ai/ollama/model/load [post]
|
||||||
|
func (b *BaseApi) LoadOllamaModelDetail(c *gin.Context) {
|
||||||
|
var req dto.OllamaModelName
|
||||||
|
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
detail, err := AIToolService.LoadDetail(req.Name)
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
helper.SuccessWithData(c, detail)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags AI
|
||||||
|
// @Summary Delete Ollama model
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body dto.ForceDelete true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Security Timestamp
|
||||||
|
// @Router /ai/ollama/model/del [post]
|
||||||
|
// @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"ids","isList":true,"db":"ollama_models","output_column":"name","output_value":"names"}],"formatZH":"删除 Ollama 模型 [names]","formatEN":"remove Ollama model [names]"}
|
||||||
|
func (b *BaseApi) DeleteOllamaModel(c *gin.Context) {
|
||||||
|
var req dto.ForceDelete
|
||||||
|
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := AIToolService.Delete(req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
helper.SuccessWithOutData(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags AI
|
||||||
|
// @Summary Load gpu / xpu info
|
||||||
|
// @Accept json
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Security Timestamp
|
||||||
|
// @Router /ai/gpu/load [get]
|
||||||
|
func (b *BaseApi) LoadGpuInfo(c *gin.Context) {
|
||||||
|
ok, client := gpu.New()
|
||||||
|
if ok {
|
||||||
|
info, err := client.LoadGpuInfo()
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, info)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
xpuOK, xpuClient := xpu.New()
|
||||||
|
if xpuOK {
|
||||||
|
info, err := xpuClient.LoadGpuInfo()
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, info)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, &common.GpuInfo{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags AI
|
||||||
|
// @Summary Bind domain
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body dto.OllamaBindDomain true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Security Timestamp
|
||||||
|
// @Router /ai/domain/bind [post]
|
||||||
|
func (b *BaseApi) BindDomain(c *gin.Context) {
|
||||||
|
var req dto.OllamaBindDomain
|
||||||
|
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := AIToolService.BindDomain(req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithOutData(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags AI
|
||||||
|
// @Summary Get bind domain
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body dto.OllamaBindDomainReq true "request"
|
||||||
|
// @Success 200 {object} dto.OllamaBindDomainRes
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Security Timestamp
|
||||||
|
// @Router /ai/domain/get [post]
|
||||||
|
func (b *BaseApi) GetBindDomain(c *gin.Context) {
|
||||||
|
var req dto.OllamaBindDomainReq
|
||||||
|
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
res, err := AIToolService.GetBindDomain(req)
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tags AI
|
||||||
|
// Summary Update bind domain
|
||||||
|
// Accept json
|
||||||
|
// Param request body dto.OllamaBindDomain true "request"
|
||||||
|
// Success 200
|
||||||
|
// Security ApiKeyAuth
|
||||||
|
// Security Timestamp
|
||||||
|
// Router /ai/domain/update [post]
|
||||||
|
func (b *BaseApi) UpdateBindDomain(c *gin.Context) {
|
||||||
|
var req dto.OllamaBindDomain
|
||||||
|
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := AIToolService.UpdateBindDomain(req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithOutData(c)
|
||||||
|
}
|
||||||
+10
-10
@@ -13,7 +13,7 @@ import (
|
|||||||
// @Summary List apps
|
// @Summary List apps
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body request.AppSearch true "request"
|
// @Param request body request.AppSearch true "request"
|
||||||
// @Success 200
|
// @Success 200 {object} response.AppRes
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /apps/search [post]
|
// @Router /apps/search [post]
|
||||||
@@ -22,7 +22,7 @@ func (b *BaseApi) SearchApp(c *gin.Context) {
|
|||||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
list, err := appService.PageApp(req)
|
list, err := appService.PageApp(c, req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
return
|
return
|
||||||
@@ -68,14 +68,14 @@ func (b *BaseApi) SyncApp(c *gin.Context) {
|
|||||||
// @Success 200 {object} response.AppDTO
|
// @Success 200 {object} response.AppDTO
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /apps/:key [get]
|
// @Router /apps/{key} [get]
|
||||||
func (b *BaseApi) GetApp(c *gin.Context) {
|
func (b *BaseApi) GetApp(c *gin.Context) {
|
||||||
appKey, err := helper.GetStrParamByKey(c, "key")
|
appKey, err := helper.GetStrParamByKey(c, "key")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
appDTO, err := appService.GetApp(appKey)
|
appDTO, err := appService.GetApp(c, appKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
return
|
return
|
||||||
@@ -88,11 +88,11 @@ func (b *BaseApi) GetApp(c *gin.Context) {
|
|||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param appId path integer true "app id"
|
// @Param appId path integer true "app id"
|
||||||
// @Param version path string true "app version"
|
// @Param version path string true "app version"
|
||||||
// @Param version path string true "app type"
|
// @Param type path string true "app type"
|
||||||
// @Success 200 {object} response.AppDetailDTO
|
// @Success 200 {object} response.AppDetailDTO
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /apps/detail/:appId/:version/:type [get]
|
// @Router /apps/detail/{appId}/{version}/{type} [get]
|
||||||
func (b *BaseApi) GetAppDetail(c *gin.Context) {
|
func (b *BaseApi) GetAppDetail(c *gin.Context) {
|
||||||
appID, err := helper.GetIntParamByKey(c, "appId")
|
appID, err := helper.GetIntParamByKey(c, "appId")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -112,11 +112,11 @@ func (b *BaseApi) GetAppDetail(c *gin.Context) {
|
|||||||
// @Tags App
|
// @Tags App
|
||||||
// @Summary Get app detail by id
|
// @Summary Get app detail by id
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param appId path integer true "id"
|
// @Param id path integer true "id"
|
||||||
// @Success 200 {object} response.AppDetailDTO
|
// @Success 200 {object} response.AppDetailDTO
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /apps/details/:id [get]
|
// @Router /apps/details/{id} [get]
|
||||||
func (b *BaseApi) GetAppDetailByID(c *gin.Context) {
|
func (b *BaseApi) GetAppDetailByID(c *gin.Context) {
|
||||||
appDetailID, err := helper.GetIntParamByKey(c, "id")
|
appDetailID, err := helper.GetIntParamByKey(c, "id")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -173,7 +173,7 @@ func (b *BaseApi) InstallApp(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (b *BaseApi) GetAppTags(c *gin.Context) {
|
func (b *BaseApi) GetAppTags(c *gin.Context) {
|
||||||
tags, err := appService.GetAppTags()
|
tags, err := appService.GetAppTags(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
return
|
return
|
||||||
@@ -183,7 +183,7 @@ func (b *BaseApi) GetAppTags(c *gin.Context) {
|
|||||||
|
|
||||||
// @Tags App
|
// @Tags App
|
||||||
// @Summary Get app list update
|
// @Summary Get app list update
|
||||||
// @Success 200
|
// @Success 200 {object} response.AppUpdateRes
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /apps/checkupdate [get]
|
// @Router /apps/checkupdate [get]
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import (
|
|||||||
// @Summary Page app installed
|
// @Summary Page app installed
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body request.AppInstalledSearch true "request"
|
// @Param request body request.AppInstalledSearch true "request"
|
||||||
// @Success 200
|
// @Success 200 {object} dto.PageResult
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /apps/installed/search [post]
|
// @Router /apps/installed/search [post]
|
||||||
@@ -28,7 +28,10 @@ func (b *BaseApi) SearchAppInstalled(c *gin.Context) {
|
|||||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
helper.SuccessWithData(c, list)
|
helper.SuccessWithData(c, dto.PageResult{
|
||||||
|
Items: list,
|
||||||
|
Total: int64(len(list)),
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
total, list, err := appInstallService.Page(req)
|
total, list, err := appInstallService.Page(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -45,7 +48,7 @@ func (b *BaseApi) SearchAppInstalled(c *gin.Context) {
|
|||||||
// @Tags App
|
// @Tags App
|
||||||
// @Summary List app installed
|
// @Summary List app installed
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Success 200 array dto.AppInstallInfo
|
// @Success 200 {array} dto.AppInstallInfo
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /apps/installed/list [get]
|
// @Router /apps/installed/list [get]
|
||||||
@@ -104,10 +107,11 @@ func (b *BaseApi) LoadPort(c *gin.Context) {
|
|||||||
// @Summary Search app password by key
|
// @Summary Search app password by key
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body dto.OperationWithNameAndType true "request"
|
// @Param request body dto.OperationWithNameAndType true "request"
|
||||||
// @Success 200 {string} response.DatabaseConn
|
// @Param key path string true "key"
|
||||||
|
// @Success 200 {object} response.DatabaseConn
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /apps/installed/conninfo/:key [get]
|
// @Router /apps/installed/conninfo/{key} [get]
|
||||||
func (b *BaseApi) LoadConnInfo(c *gin.Context) {
|
func (b *BaseApi) LoadConnInfo(c *gin.Context) {
|
||||||
var req dto.OperationWithNameAndType
|
var req dto.OperationWithNameAndType
|
||||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||||
@@ -128,7 +132,7 @@ func (b *BaseApi) LoadConnInfo(c *gin.Context) {
|
|||||||
// @Success 200 {array} dto.AppResource
|
// @Success 200 {array} dto.AppResource
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /apps/installed/delete/check/:appInstallId [get]
|
// @Router /apps/installed/delete/check/{appInstallId} [get]
|
||||||
func (b *BaseApi) DeleteCheck(c *gin.Context) {
|
func (b *BaseApi) DeleteCheck(c *gin.Context) {
|
||||||
appInstallId, err := helper.GetIntParamByKey(c, "appInstallId")
|
appInstallId, err := helper.GetIntParamByKey(c, "appInstallId")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -187,7 +191,7 @@ func (b *BaseApi) OperateInstalled(c *gin.Context) {
|
|||||||
// @Success 200 {array} response.AppService
|
// @Success 200 {array} response.AppService
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /apps/services/:key [get]
|
// @Router /apps/services/{key} [get]
|
||||||
func (b *BaseApi) GetServices(c *gin.Context) {
|
func (b *BaseApi) GetServices(c *gin.Context) {
|
||||||
key := c.Param("key")
|
key := c.Param("key")
|
||||||
services, err := appInstallService.GetServices(key)
|
services, err := appInstallService.GetServices(key)
|
||||||
@@ -201,7 +205,6 @@ func (b *BaseApi) GetServices(c *gin.Context) {
|
|||||||
// @Tags App
|
// @Tags App
|
||||||
// @Summary Search app update version by install id
|
// @Summary Search app update version by install id
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param appInstallId path integer true "request"
|
|
||||||
// @Success 200 {array} dto.AppVersion
|
// @Success 200 {array} dto.AppVersion
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
@@ -266,10 +269,10 @@ func (b *BaseApi) GetDefaultConfig(c *gin.Context) {
|
|||||||
// @Summary Search params by appInstallId
|
// @Summary Search params by appInstallId
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param appInstallId path string true "request"
|
// @Param appInstallId path string true "request"
|
||||||
// @Success 200 {object} response.AppParam
|
// @Success 200 {object} response.AppConfig
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /apps/installed/params/:appInstallId [get]
|
// @Router /apps/installed/params/{appInstallId} [get]
|
||||||
func (b *BaseApi) GetParams(c *gin.Context) {
|
func (b *BaseApi) GetParams(c *gin.Context) {
|
||||||
appInstallId, err := helper.GetIntParamByKey(c, "appInstallId")
|
appInstallId, err := helper.GetIntParamByKey(c, "appInstallId")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
+18
-14
@@ -2,6 +2,7 @@ package v1
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||||
@@ -9,7 +10,6 @@ import (
|
|||||||
"github.com/1Panel-dev/1Panel/backend/global"
|
"github.com/1Panel-dev/1Panel/backend/global"
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/captcha"
|
"github.com/1Panel-dev/1Panel/backend/utils/captcha"
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/geo"
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -28,7 +28,9 @@ func (b *BaseApi) Login(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if req.AuthMethod != "jwt" && !req.IgnoreCaptcha {
|
ip := common.GetRealClientIP(c)
|
||||||
|
needCaptcha := global.IPTracker.NeedCaptcha(ip)
|
||||||
|
if needCaptcha {
|
||||||
if err := captcha.VerifyCode(req.CaptchaID, req.Captcha); err != nil {
|
if err := captcha.VerifyCode(req.CaptchaID, req.Captcha); err != nil {
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
return
|
return
|
||||||
@@ -50,9 +52,11 @@ func (b *BaseApi) Login(c *gin.Context) {
|
|||||||
user, err := authService.Login(c, req, string(entrance))
|
user, err := authService.Login(c, req, string(entrance))
|
||||||
go saveLoginLogs(c, err)
|
go saveLoginLogs(c, err)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
global.IPTracker.SetNeedCaptcha(ip)
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
global.IPTracker.Clear(ip)
|
||||||
helper.SuccessWithData(c, user)
|
helper.SuccessWithData(c, user)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,7 +125,7 @@ func (b *BaseApi) GetResponsePage(c *gin.Context) {
|
|||||||
|
|
||||||
// @Tags Auth
|
// @Tags Auth
|
||||||
// @Summary Check System isDemo
|
// @Summary Check System isDemo
|
||||||
// @Success 200
|
// @Success 200 {boolean} isDemo
|
||||||
// @Router /auth/demo [get]
|
// @Router /auth/demo [get]
|
||||||
func (b *BaseApi) CheckIsDemo(c *gin.Context) {
|
func (b *BaseApi) CheckIsDemo(c *gin.Context) {
|
||||||
helper.SuccessWithData(c, global.CONF.System.IsDemo)
|
helper.SuccessWithData(c, global.CONF.System.IsDemo)
|
||||||
@@ -129,23 +133,28 @@ func (b *BaseApi) CheckIsDemo(c *gin.Context) {
|
|||||||
|
|
||||||
// @Tags Auth
|
// @Tags Auth
|
||||||
// @Summary Check System isIntl
|
// @Summary Check System isIntl
|
||||||
// @Success 200
|
// @Success 200 {boolean} isIntl
|
||||||
// @Router /auth/intl [get]
|
// @Router /auth/intl [get]
|
||||||
func (b *BaseApi) CheckIsIntl(c *gin.Context) {
|
func (b *BaseApi) CheckIsIntl(c *gin.Context) {
|
||||||
helper.SuccessWithData(c, global.CONF.System.IsIntl)
|
helper.SuccessWithData(c, global.CONF.System.IsIntl)
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Tags Auth
|
// @Tags Auth
|
||||||
// @Summary Load System Language
|
// @Summary Load System Setting for login
|
||||||
// @Success 200
|
// @Success 200 {object} dto.LoginSetting
|
||||||
// @Router /auth/language [get]
|
// @Router /auth/setting [get]
|
||||||
func (b *BaseApi) GetLanguage(c *gin.Context) {
|
func (b *BaseApi) GetAuthSetting(c *gin.Context) {
|
||||||
settingInfo, err := settingService.GetSettingInfo()
|
settingInfo, err := settingService.GetSettingInfo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
helper.SuccessWithData(c, settingInfo.Language)
|
ip := common.GetRealClientIP(c)
|
||||||
|
needCaptcha := global.IPTracker.NeedCaptcha(ip)
|
||||||
|
helper.SuccessWithData(c, dto.LoginSetting{
|
||||||
|
NeedCaptcha: needCaptcha,
|
||||||
|
Language: settingInfo.Language,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func saveLoginLogs(c *gin.Context, err error) {
|
func saveLoginLogs(c *gin.Context, err error) {
|
||||||
@@ -157,11 +166,6 @@ func saveLoginLogs(c *gin.Context, err error) {
|
|||||||
logs.Status = constant.StatusSuccess
|
logs.Status = constant.StatusSuccess
|
||||||
}
|
}
|
||||||
logs.IP = c.ClientIP()
|
logs.IP = c.ClientIP()
|
||||||
address, err := geo.GetIPLocation(logs.IP, common.GetLang(c))
|
|
||||||
if err != nil {
|
|
||||||
global.LOG.Errorf("get ip location failed: %s", err)
|
|
||||||
}
|
|
||||||
logs.Agent = c.GetHeader("User-Agent")
|
logs.Agent = c.GetHeader("User-Agent")
|
||||||
logs.Address = address
|
|
||||||
_ = logService.CreateLoginLog(logs)
|
_ = logService.CreateLoginLog(logs)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ func (b *BaseApi) RefreshOneDriveToken(c *gin.Context) {
|
|||||||
// @Summary List buckets
|
// @Summary List buckets
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body dto.ForBuckets true "request"
|
// @Param request body dto.ForBuckets true "request"
|
||||||
// @Success 200 {array} string
|
// @Success 200 {array} object
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /settings/backup/search [post]
|
// @Router /settings/backup/search [post]
|
||||||
@@ -140,7 +140,7 @@ func (b *BaseApi) DeleteBackup(c *gin.Context) {
|
|||||||
// @Summary Page backup records
|
// @Summary Page backup records
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body dto.RecordSearch true "request"
|
// @Param request body dto.RecordSearch true "request"
|
||||||
// @Success 200
|
// @Success 200 {object} dto.PageResult
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /settings/backup/record/search [post]
|
// @Router /settings/backup/record/search [post]
|
||||||
@@ -162,11 +162,34 @@ func (b *BaseApi) SearchBackupRecords(c *gin.Context) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @Tags Backup Account
|
||||||
|
// @Summary Load backup records size
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body dto.RecordSearch true "request"
|
||||||
|
// @Success 200 {array} dto.BackupFile
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Security Timestamp
|
||||||
|
// @Router /settings/backup/record/size [post]
|
||||||
|
func (b *BaseApi) LoadBackupSize(c *gin.Context) {
|
||||||
|
var req dto.RecordSearch
|
||||||
|
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
list, err := backupService.LoadSize(req)
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
helper.SuccessWithData(c, list)
|
||||||
|
}
|
||||||
|
|
||||||
// @Tags Backup Account
|
// @Tags Backup Account
|
||||||
// @Summary Page backup records by cronjob
|
// @Summary Page backup records by cronjob
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body dto.RecordSearchByCronjob true "request"
|
// @Param request body dto.RecordSearchByCronjob true "request"
|
||||||
// @Success 200
|
// @Success 200 {object} dto.PageResult
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /settings/backup/record/search/bycronjob [post]
|
// @Router /settings/backup/record/search/bycronjob [post]
|
||||||
@@ -188,11 +211,34 @@ func (b *BaseApi) SearchBackupRecordsByCronjob(c *gin.Context) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @Tags Backup Account
|
||||||
|
// @Summary Load backup records size for cronjob
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body dto.RecordSearchByCronjob true "request"
|
||||||
|
// @Success 200 {array} dto.BackupFile
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Security Timestamp
|
||||||
|
// @Router /settings/backup/record/size/bycronjob [post]
|
||||||
|
func (b *BaseApi) LoadBackupSizeByCronjob(c *gin.Context) {
|
||||||
|
var req dto.RecordSearchByCronjob
|
||||||
|
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
list, err := backupService.LoadSizeByCronjob(req)
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
helper.SuccessWithData(c, list)
|
||||||
|
}
|
||||||
|
|
||||||
// @Tags Backup Account
|
// @Tags Backup Account
|
||||||
// @Summary Download backup record
|
// @Summary Download backup record
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body dto.DownloadRecord true "request"
|
// @Param request body dto.DownloadRecord true "request"
|
||||||
// @Success 200
|
// @Success 200 {string} filePath
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /settings/backup/record/download [post]
|
// @Router /settings/backup/record/download [post]
|
||||||
|
|||||||
@@ -120,6 +120,7 @@ func (b *BaseApi) LoadClamBaseInfo(c *gin.Context) {
|
|||||||
// @Summary Operate Clam
|
// @Summary Operate Clam
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body dto.Operate true "request"
|
// @Param request body dto.Operate true "request"
|
||||||
|
// @Success 200
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /toolbox/clam/operate [post]
|
// @Router /toolbox/clam/operate [post]
|
||||||
@@ -142,6 +143,7 @@ func (b *BaseApi) OperateClam(c *gin.Context) {
|
|||||||
// @Summary Clean clam record
|
// @Summary Clean clam record
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body dto.OperateByID true "request"
|
// @Param request body dto.OperateByID true "request"
|
||||||
|
// @Success 200
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /toolbox/clam/record/clean [post]
|
// @Router /toolbox/clam/record/clean [post]
|
||||||
@@ -189,7 +191,7 @@ func (b *BaseApi) SearchClamRecord(c *gin.Context) {
|
|||||||
// @Summary Load clam record detail
|
// @Summary Load clam record detail
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body dto.ClamLogReq true "request"
|
// @Param request body dto.ClamLogReq true "request"
|
||||||
// @Success 200
|
// @Success 200 {string} content
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /toolbox/clam/record/log [post]
|
// @Router /toolbox/clam/record/log [post]
|
||||||
@@ -212,7 +214,7 @@ func (b *BaseApi) LoadClamRecordLog(c *gin.Context) {
|
|||||||
// @Summary Load clam file
|
// @Summary Load clam file
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body dto.ClamFileReq true "request"
|
// @Param request body dto.ClamFileReq true "request"
|
||||||
// @Success 200 {object} dto.PageResult
|
// @Success 200 {string} content
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /toolbox/clam/file/search [post]
|
// @Router /toolbox/clam/file/search [post]
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ func (b *BaseApi) SearchRedisCommand(c *gin.Context) {
|
|||||||
// @Tags Command
|
// @Tags Command
|
||||||
// @Summary Tree commands
|
// @Summary Tree commands
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Success 200 {Array} dto.CommandTree
|
// @Success 200 {array} dto.CommandTree
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /hosts/command/tree [get]
|
// @Router /hosts/command/tree [get]
|
||||||
@@ -122,7 +122,7 @@ func (b *BaseApi) SearchCommandTree(c *gin.Context) {
|
|||||||
|
|
||||||
// @Tags Redis Command
|
// @Tags Redis Command
|
||||||
// @Summary List redis commands
|
// @Summary List redis commands
|
||||||
// @Success 200 {Array} dto.RedisCommand
|
// @Success 200 {array} dto.RedisCommand
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /hosts/command/redis [get]
|
// @Router /hosts/command/redis [get]
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
package v1
|
package v1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||||
"github.com/1Panel-dev/1Panel/backend/global"
|
"github.com/1Panel-dev/1Panel/backend/global"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"strconv"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// @Tags Container
|
// @Tags Container
|
||||||
@@ -40,7 +41,7 @@ func (b *BaseApi) SearchContainer(c *gin.Context) {
|
|||||||
// @Summary List containers
|
// @Summary List containers
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200
|
// @Success 200 {array} string
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /containers/list [post]
|
// @Router /containers/list [post]
|
||||||
@@ -82,7 +83,7 @@ func (b *BaseApi) SearchCompose(c *gin.Context) {
|
|||||||
// @Summary Test compose
|
// @Summary Test compose
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body dto.ComposeCreate true "request"
|
// @Param request body dto.ComposeCreate true "request"
|
||||||
// @Success 200
|
// @Success 200 {boolean} isOK
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /containers/compose/test [post]
|
// @Router /containers/compose/test [post]
|
||||||
@@ -105,7 +106,7 @@ func (b *BaseApi) TestCompose(c *gin.Context) {
|
|||||||
// @Summary Create compose
|
// @Summary Create compose
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body dto.ComposeCreate true "request"
|
// @Param request body dto.ComposeCreate true "request"
|
||||||
// @Success 200
|
// @Success 200 {string} log
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /containers/compose [post]
|
// @Router /containers/compose [post]
|
||||||
@@ -311,7 +312,7 @@ func (b *BaseApi) CleanContainerLog(c *gin.Context) {
|
|||||||
// @Summary Load container log
|
// @Summary Load container log
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body dto.OperationWithNameAndType true "request"
|
// @Param request body dto.OperationWithNameAndType true "request"
|
||||||
// @Success 200
|
// @Success 200 {string} content
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /containers/load/log [post]
|
// @Router /containers/load/log [post]
|
||||||
@@ -390,11 +391,11 @@ func (b *BaseApi) ContainerOperation(c *gin.Context) {
|
|||||||
|
|
||||||
// @Tags Container
|
// @Tags Container
|
||||||
// @Summary Container stats
|
// @Summary Container stats
|
||||||
// @Param id path integer true "container id"
|
// @Param id path string true "container id"
|
||||||
// @Success 200 {object} dto.ContainerStats
|
// @Success 200 {object} dto.ContainerStats
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /containers/stats/:id [get]
|
// @Router /containers/stats/{id} [get]
|
||||||
func (b *BaseApi) ContainerStats(c *gin.Context) {
|
func (b *BaseApi) ContainerStats(c *gin.Context) {
|
||||||
containerID, ok := c.Params.Get("id")
|
containerID, ok := c.Params.Get("id")
|
||||||
if !ok {
|
if !ok {
|
||||||
@@ -438,6 +439,7 @@ func (b *BaseApi) Inspect(c *gin.Context) {
|
|||||||
// @Param since query string false "since"
|
// @Param since query string false "since"
|
||||||
// @Param follow query string false "follow"
|
// @Param follow query string false "follow"
|
||||||
// @Param tail query string false "tail"
|
// @Param tail query string false "tail"
|
||||||
|
// @Success 200
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /containers/search/log [post]
|
// @Router /containers/search/log [post]
|
||||||
@@ -464,6 +466,7 @@ func (b *BaseApi) ContainerLogs(c *gin.Context) {
|
|||||||
// @Summary Download Container logs
|
// @Summary Download Container logs
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body dto.ContainerLog true "request"
|
// @Param request body dto.ContainerLog true "request"
|
||||||
|
// @Success 200
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /containers/download/log [post]
|
// @Router /containers/download/log [post]
|
||||||
@@ -680,6 +683,7 @@ func (b *BaseApi) ComposeUpdate(c *gin.Context) {
|
|||||||
// @Param since query string false "date"
|
// @Param since query string false "date"
|
||||||
// @Param follow query string false "follow"
|
// @Param follow query string false "follow"
|
||||||
// @Param tail query string false "tail"
|
// @Param tail query string false "tail"
|
||||||
|
// @Success 200
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /containers/compose/search/log [get]
|
// @Router /containers/compose/search/log [get]
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ func (b *BaseApi) SearchJobRecords(c *gin.Context) {
|
|||||||
// @Summary Load Cronjob record log
|
// @Summary Load Cronjob record log
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body dto.OperateByID true "request"
|
// @Param request body dto.OperateByID true "request"
|
||||||
// @Success 200
|
// @Success 200 {string} content
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /cronjobs/records/log [post]
|
// @Router /cronjobs/records/log [post]
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ func (b *BaseApi) LoadDashboardOsInfo(c *gin.Context) {
|
|||||||
// @Success 200 {object} dto.DashboardBase
|
// @Success 200 {object} dto.DashboardBase
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /dashboard/base/:ioOption/:netOption [get]
|
// @Router /dashboard/base/{ioOption}/{netOption} [get]
|
||||||
func (b *BaseApi) LoadDashboardBaseInfo(c *gin.Context) {
|
func (b *BaseApi) LoadDashboardBaseInfo(c *gin.Context) {
|
||||||
ioOption, ok := c.Params.Get("ioOption")
|
ioOption, ok := c.Params.Get("ioOption")
|
||||||
if !ok {
|
if !ok {
|
||||||
@@ -78,7 +78,7 @@ func (b *BaseApi) LoadDashboardCurrentInfo(c *gin.Context) {
|
|||||||
// @Success 200
|
// @Success 200
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /dashboard/system/restart/:operation [post]
|
// @Router /dashboard/system/restart/{operation} [post]
|
||||||
func (b *BaseApi) SystemRestart(c *gin.Context) {
|
func (b *BaseApi) SystemRestart(c *gin.Context) {
|
||||||
operation, ok := c.Params.Get("operation")
|
operation, ok := c.Params.Get("operation")
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ func (b *BaseApi) CreateDatabase(c *gin.Context) {
|
|||||||
// @Summary Check database
|
// @Summary Check database
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body dto.DatabaseCreate true "request"
|
// @Param request body dto.DatabaseCreate true "request"
|
||||||
// @Success 200
|
// @Success 200 {boolean} isOk
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /databases/db/check [post]
|
// @Router /databases/db/check [post]
|
||||||
@@ -93,10 +93,11 @@ func (b *BaseApi) SearchDatabase(c *gin.Context) {
|
|||||||
|
|
||||||
// @Tags Database
|
// @Tags Database
|
||||||
// @Summary List databases
|
// @Summary List databases
|
||||||
|
// @Param type path string true "type"
|
||||||
// @Success 200 {array} dto.DatabaseOption
|
// @Success 200 {array} dto.DatabaseOption
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /databases/db/list/:type [get]
|
// @Router /databases/db/list/{type} [get]
|
||||||
func (b *BaseApi) ListDatabase(c *gin.Context) {
|
func (b *BaseApi) ListDatabase(c *gin.Context) {
|
||||||
dbType, err := helper.GetStrParamByKey(c, "type")
|
dbType, err := helper.GetStrParamByKey(c, "type")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -114,10 +115,11 @@ func (b *BaseApi) ListDatabase(c *gin.Context) {
|
|||||||
|
|
||||||
// @Tags Database
|
// @Tags Database
|
||||||
// @Summary Retrieve database list based on type
|
// @Summary Retrieve database list based on type
|
||||||
|
// @Param type path string true "type"
|
||||||
// @Success 200 {array} dto.DatabaseItem
|
// @Success 200 {array} dto.DatabaseItem
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /databases/db/item/:type [get]
|
// @Router /databases/db/item/{type} [get]
|
||||||
func (b *BaseApi) LoadDatabaseItems(c *gin.Context) {
|
func (b *BaseApi) LoadDatabaseItems(c *gin.Context) {
|
||||||
dbType, err := helper.GetStrParamByKey(c, "type")
|
dbType, err := helper.GetStrParamByKey(c, "type")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -135,10 +137,11 @@ func (b *BaseApi) LoadDatabaseItems(c *gin.Context) {
|
|||||||
|
|
||||||
// @Tags Database
|
// @Tags Database
|
||||||
// @Summary Get databases
|
// @Summary Get databases
|
||||||
|
// @Param name path string true "name"
|
||||||
// @Success 200 {object} dto.DatabaseInfo
|
// @Success 200 {object} dto.DatabaseInfo
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /databases/db/:name [get]
|
// @Router /databases/db/{name} [get]
|
||||||
func (b *BaseApi) GetDatabase(c *gin.Context) {
|
func (b *BaseApi) GetDatabase(c *gin.Context) {
|
||||||
name, err := helper.GetStrParamByKey(c, "name")
|
name, err := helper.GetStrParamByKey(c, "name")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ func (b *BaseApi) LoadDBBaseInfo(c *gin.Context) {
|
|||||||
// @Summary Load Database conf
|
// @Summary Load Database conf
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body dto.OperationWithNameAndType true "request"
|
// @Param request body dto.OperationWithNameAndType true "request"
|
||||||
// @Success 200
|
// @Success 200 {string} content
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /databases/common/load/file [post]
|
// @Router /databases/common/load/file [post]
|
||||||
|
|||||||
@@ -217,6 +217,7 @@ func (b *BaseApi) ListDBName(c *gin.Context) {
|
|||||||
// @Summary Load mysql database from remote
|
// @Summary Load mysql database from remote
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body dto.MysqlLoadDB true "request"
|
// @Param request body dto.MysqlLoadDB true "request"
|
||||||
|
// @Success 200
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /databases/load [post]
|
// @Router /databases/load [post]
|
||||||
|
|||||||
@@ -168,9 +168,11 @@ func (b *BaseApi) SearchPostgresql(c *gin.Context) {
|
|||||||
// @Summary Load postgresql database from remote
|
// @Summary Load postgresql database from remote
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body dto.PostgresqlLoadDB true "request"
|
// @Param request body dto.PostgresqlLoadDB true "request"
|
||||||
|
// @Param database path string true "database"
|
||||||
|
// @Success 200
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /databases/pg/:database/load [post]
|
// @Router /databases/pg/{database}/load [post]
|
||||||
func (b *BaseApi) LoadPostgresqlDBFromRemote(c *gin.Context) {
|
func (b *BaseApi) LoadPostgresqlDBFromRemote(c *gin.Context) {
|
||||||
database, err := helper.GetStrParamByKey(c, "database")
|
database, err := helper.GetStrParamByKey(c, "database")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ func (b *BaseApi) LoadDeviceBaseInfo(c *gin.Context) {
|
|||||||
// @Tags Device
|
// @Tags Device
|
||||||
// @Summary list time zone options
|
// @Summary list time zone options
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Success 200 {Array} string
|
// @Success 200 {array} string
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /toolbox/device/zone/options [get]
|
// @Router /toolbox/device/zone/options [get]
|
||||||
@@ -46,7 +46,7 @@ func (b *BaseApi) LoadTimeOption(c *gin.Context) {
|
|||||||
// @Summary load conf
|
// @Summary load conf
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body dto.OperationWithName true "request"
|
// @Param request body dto.OperationWithName true "request"
|
||||||
// @Success 200
|
// @Success 200 {array} string
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /toolbox/device/conf [post]
|
// @Router /toolbox/device/conf [post]
|
||||||
@@ -185,7 +185,7 @@ func (b *BaseApi) UpdateDeviceSwap(c *gin.Context) {
|
|||||||
// @Summary Check device DNS conf
|
// @Summary Check device DNS conf
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body dto.SettingUpdate true "request"
|
// @Param request body dto.SettingUpdate true "request"
|
||||||
// @Success 200
|
// @Success 200 {boolean} data
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /toolbox/device/check/dns [post]
|
// @Router /toolbox/device/check/dns [post]
|
||||||
@@ -206,7 +206,7 @@ func (b *BaseApi) CheckDNS(c *gin.Context) {
|
|||||||
|
|
||||||
// @Tags Device
|
// @Tags Device
|
||||||
// @Summary Scan system
|
// @Summary Scan system
|
||||||
// @Success 200
|
// @Success 200 {object} dto.CleanData
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /toolbox/scan [post]
|
// @Router /toolbox/scan [post]
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ var (
|
|||||||
appService = service.NewIAppService()
|
appService = service.NewIAppService()
|
||||||
appInstallService = service.NewIAppInstalledService()
|
appInstallService = service.NewIAppInstalledService()
|
||||||
|
|
||||||
|
AIToolService = service.NewIAIToolService()
|
||||||
|
|
||||||
containerService = service.NewIContainerService()
|
containerService = service.NewIContainerService()
|
||||||
composeTemplateService = service.NewIComposeTemplateService()
|
composeTemplateService = service.NewIComposeTemplateService()
|
||||||
imageRepoService = service.NewIImageRepoService()
|
imageRepoService = service.NewIImageRepoService()
|
||||||
@@ -66,4 +68,6 @@ var (
|
|||||||
favoriteService = service.NewIFavoriteService()
|
favoriteService = service.NewIFavoriteService()
|
||||||
|
|
||||||
websiteCAService = service.NewIWebsiteCAService()
|
websiteCAService = service.NewIWebsiteCAService()
|
||||||
|
|
||||||
|
mcpServerService = service.NewIMcpServerService()
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ func (b *BaseApi) LoadFail2BanBaseInfo(c *gin.Context) {
|
|||||||
// @Summary Page fail2ban ip list
|
// @Summary Page fail2ban ip list
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body dto.Fail2BanSearch true "request"
|
// @Param request body dto.Fail2BanSearch true "request"
|
||||||
// @Success 200 {Array} string
|
// @Success 200 {array} string
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /toolbox/fail2ban/search [post]
|
// @Router /toolbox/fail2ban/search [post]
|
||||||
@@ -52,6 +52,7 @@ func (b *BaseApi) SearchFail2Ban(c *gin.Context) {
|
|||||||
// @Summary Operate fail2ban
|
// @Summary Operate fail2ban
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body dto.Operate true "request"
|
// @Param request body dto.Operate true "request"
|
||||||
|
// @Success 200
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /toolbox/fail2ban/operate [post]
|
// @Router /toolbox/fail2ban/operate [post]
|
||||||
@@ -74,6 +75,7 @@ func (b *BaseApi) OperateFail2Ban(c *gin.Context) {
|
|||||||
// @Summary Operate sshd of fail2ban
|
// @Summary Operate sshd of fail2ban
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body dto.Operate true "request"
|
// @Param request body dto.Operate true "request"
|
||||||
|
// @Success 200
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /toolbox/fail2ban/operate/sshd [post]
|
// @Router /toolbox/fail2ban/operate/sshd [post]
|
||||||
@@ -116,7 +118,7 @@ func (b *BaseApi) UpdateFail2BanConf(c *gin.Context) {
|
|||||||
// @Tags Fail2ban
|
// @Tags Fail2ban
|
||||||
// @Summary Load fail2ban conf
|
// @Summary Load fail2ban conf
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Success 200
|
// @Success 200 {string} file
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /toolbox/fail2ban/load/conf [get]
|
// @Router /toolbox/fail2ban/load/conf [get]
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import (
|
|||||||
// @Summary List favorites
|
// @Summary List favorites
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body dto.PageInfo true "request"
|
// @Param request body dto.PageInfo true "request"
|
||||||
// @Success 200
|
// @Success 200 {object} dto.PageResult
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /files/favorite/search [post]
|
// @Router /files/favorite/search [post]
|
||||||
@@ -36,7 +36,7 @@ func (b *BaseApi) SearchFavorite(c *gin.Context) {
|
|||||||
// @Summary Create favorite
|
// @Summary Create favorite
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body request.FavoriteCreate true "request"
|
// @Param request body request.FavoriteCreate true "request"
|
||||||
// @Success 200
|
// @Success 200 {object} model.Favorite
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /files/favorite [post]
|
// @Router /files/favorite [post]
|
||||||
|
|||||||
+38
-10
@@ -39,19 +39,19 @@ func (b *BaseApi) ListFiles(c *gin.Context) {
|
|||||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
files, err := fileService.GetFileList(req)
|
fileList, err := fileService.GetFileList(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
helper.SuccessWithData(c, files)
|
helper.SuccessWithData(c, fileList)
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Tags File
|
// @Tags File
|
||||||
// @Summary Page file
|
// @Summary Page file
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body request.SearchUploadWithPage true "request"
|
// @Param request body request.SearchUploadWithPage true "request"
|
||||||
// @Success 200 {array} response.FileInfo
|
// @Success 200 {object} dto.PageResult
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /files/upload/search [post]
|
// @Router /files/upload/search [post]
|
||||||
@@ -290,6 +290,7 @@ func (b *BaseApi) SaveContent(c *gin.Context) {
|
|||||||
|
|
||||||
// @Tags File
|
// @Tags File
|
||||||
// @Summary Upload file
|
// @Summary Upload file
|
||||||
|
// @Accept multipart/form-data
|
||||||
// @Param file formData file true "request"
|
// @Param file formData file true "request"
|
||||||
// @Success 200
|
// @Success 200
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
@@ -400,7 +401,7 @@ func (b *BaseApi) UploadFiles(c *gin.Context) {
|
|||||||
// @Summary Check file exist
|
// @Summary Check file exist
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body request.FilePathCheck true "request"
|
// @Param request body request.FilePathCheck true "request"
|
||||||
// @Success 200
|
// @Success 200 {boolean} isOk
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /files/check [post]
|
// @Router /files/check [post]
|
||||||
@@ -409,11 +410,37 @@ func (b *BaseApi) CheckFile(c *gin.Context) {
|
|||||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if _, err := os.Stat(req.Path); err != nil {
|
fileOp := files.NewFileOp()
|
||||||
helper.SuccessWithData(c, false)
|
if fileOp.Stat(req.Path) {
|
||||||
|
helper.SuccessWithData(c, true)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
helper.SuccessWithData(c, true)
|
if req.WithInit {
|
||||||
|
if err := fileOp.CreateDir(req.Path, 0644); err != nil {
|
||||||
|
helper.SuccessWithData(c, false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, true)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags File
|
||||||
|
// @Summary Batch check file exist
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body request.FilePathsCheck true "request"
|
||||||
|
// @Success 200 {array} response.ExistFileInfo
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Security Timestamp
|
||||||
|
// @Router /files/batch/check [post]
|
||||||
|
func (b *BaseApi) BatchCheckFiles(c *gin.Context) {
|
||||||
|
var req request.FilePathsCheck
|
||||||
|
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fileList := fileService.BatchCheckFiles(req)
|
||||||
|
helper.SuccessWithData(c, fileList)
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Tags File
|
// @Tags File
|
||||||
@@ -441,7 +468,7 @@ func (b *BaseApi) ChangeFileName(c *gin.Context) {
|
|||||||
// @Summary Wget file
|
// @Summary Wget file
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body request.FileWget true "request"
|
// @Param request body request.FileWget true "request"
|
||||||
// @Success 200
|
// @Success 200 {object} response.FileWgetRes
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /files/wget [post]
|
// @Router /files/wget [post]
|
||||||
@@ -583,7 +610,7 @@ func (b *BaseApi) DownloadChunkFiles(c *gin.Context) {
|
|||||||
// @Summary Load file size
|
// @Summary Load file size
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body request.DirSizeReq true "request"
|
// @Param request body request.DirSizeReq true "request"
|
||||||
// @Success 200
|
// @Success 200 {object} response.DirSizeRes
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /files/size [post]
|
// @Router /files/size [post]
|
||||||
@@ -662,6 +689,7 @@ func mergeChunks(fileName string, fileDir string, dstDir string, chunkCount int,
|
|||||||
|
|
||||||
// @Tags File
|
// @Tags File
|
||||||
// @Summary Chunk upload file
|
// @Summary Chunk upload file
|
||||||
|
// @Accept multipart/form-data
|
||||||
// @Param file formData file true "request"
|
// @Param file formData file true "request"
|
||||||
// @Success 200
|
// @Success 200
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
@@ -784,7 +812,7 @@ func (b *BaseApi) Keys(c *gin.Context) {
|
|||||||
// @Tags File
|
// @Tags File
|
||||||
// @Summary Read file by Line
|
// @Summary Read file by Line
|
||||||
// @Param request body request.FileReadByLineReq true "request"
|
// @Param request body request.FileReadByLineReq true "request"
|
||||||
// @Success 200
|
// @Success 200 {object} response.FileLineContent
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /files/read [post]
|
// @Router /files/read [post]
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ func (b *BaseApi) SearchFirewallRule(c *gin.Context) {
|
|||||||
// @Summary Page firewall status
|
// @Summary Page firewall status
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body dto.FirewallOperation true "request"
|
// @Param request body dto.FirewallOperation true "request"
|
||||||
// @Success 200 {object} dto.PageResult
|
// @Success 200
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /hosts/firewall/operate [post]
|
// @Router /hosts/firewall/operate [post]
|
||||||
@@ -203,7 +203,7 @@ func (b *BaseApi) UpdatePortRule(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// @Tags Firewall
|
// @Tags Firewall
|
||||||
// @Summary Uodate address group
|
// @Summary Update address group
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body dto.AddrRuleUpdate true "request"
|
// @Param request body dto.AddrRuleUpdate true "request"
|
||||||
// @Success 200
|
// @Success 200
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ func (b *BaseApi) LoadFtpLogInfo(c *gin.Context) {
|
|||||||
// @Summary Operate FTP
|
// @Summary Operate FTP
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body dto.Operate true "request"
|
// @Param request body dto.Operate true "request"
|
||||||
|
// @Success 200
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /toolbox/ftp/operate [post]
|
// @Router /toolbox/ftp/operate [post]
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import (
|
|||||||
// @Summary Create host
|
// @Summary Create host
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body dto.HostOperate true "request"
|
// @Param request body dto.HostOperate true "request"
|
||||||
// @Success 200
|
// @Success 200 {object} dto.HostInfo
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /hosts [post]
|
// @Router /hosts [post]
|
||||||
@@ -35,7 +35,7 @@ func (b *BaseApi) CreateHost(c *gin.Context) {
|
|||||||
// @Summary Test host conn by info
|
// @Summary Test host conn by info
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body dto.HostConnTest true "request"
|
// @Param request body dto.HostConnTest true "request"
|
||||||
// @Success 200
|
// @Success 200 {boolean} connStatus
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /hosts/test/byinfo [post]
|
// @Router /hosts/test/byinfo [post]
|
||||||
@@ -56,7 +56,7 @@ func (b *BaseApi) TestByInfo(c *gin.Context) {
|
|||||||
// @Success 200 {boolean} connStatus
|
// @Success 200 {boolean} connStatus
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /hosts/test/byid/:id [post]
|
// @Router /hosts/test/byid/{id} [post]
|
||||||
func (b *BaseApi) TestByID(c *gin.Context) {
|
func (b *BaseApi) TestByID(c *gin.Context) {
|
||||||
id, err := helper.GetParamID(c)
|
id, err := helper.GetParamID(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -95,7 +95,7 @@ func (b *BaseApi) HostTree(c *gin.Context) {
|
|||||||
// @Summary Page host
|
// @Summary Page host
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body dto.SearchHostWithPage true "request"
|
// @Param request body dto.SearchHostWithPage true "request"
|
||||||
// @Success 200 {array} dto.HostTree
|
// @Success 200 {object} dto.PageResult
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /hosts/search [post]
|
// @Router /hosts/search [post]
|
||||||
|
|||||||
@@ -11,10 +11,10 @@ import (
|
|||||||
// @Summary Get tool status
|
// @Summary Get tool status
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body request.HostToolReq true "request"
|
// @Param request body request.HostToolReq true "request"
|
||||||
// @Success 200
|
// @Success 200 {object} response.HostToolRes
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /host/tool [post]
|
// @Router /hosts/tool [post]
|
||||||
func (b *BaseApi) GetToolStatus(c *gin.Context) {
|
func (b *BaseApi) GetToolStatus(c *gin.Context) {
|
||||||
var req request.HostToolReq
|
var req request.HostToolReq
|
||||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||||
@@ -36,7 +36,7 @@ func (b *BaseApi) GetToolStatus(c *gin.Context) {
|
|||||||
// @Success 200
|
// @Success 200
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /host/tool/create [post]
|
// @Router /hosts/tool/create [post]
|
||||||
// @x-panel-log {"bodyKeys":["type"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"创建 [type] 配置","formatEN":"create [type] config"}
|
// @x-panel-log {"bodyKeys":["type"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"创建 [type] 配置","formatEN":"create [type] config"}
|
||||||
func (b *BaseApi) InitToolConfig(c *gin.Context) {
|
func (b *BaseApi) InitToolConfig(c *gin.Context) {
|
||||||
var req request.HostToolCreate
|
var req request.HostToolCreate
|
||||||
@@ -58,7 +58,7 @@ func (b *BaseApi) InitToolConfig(c *gin.Context) {
|
|||||||
// @Success 200
|
// @Success 200
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /host/tool/operate [post]
|
// @Router /hosts/tool/operate [post]
|
||||||
// @x-panel-log {"bodyKeys":["operate","type"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"[operate] [type] ","formatEN":"[operate] [type]"}
|
// @x-panel-log {"bodyKeys":["operate","type"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"[operate] [type] ","formatEN":"[operate] [type]"}
|
||||||
func (b *BaseApi) OperateTool(c *gin.Context) {
|
func (b *BaseApi) OperateTool(c *gin.Context) {
|
||||||
var req request.HostToolReq
|
var req request.HostToolReq
|
||||||
@@ -77,10 +77,10 @@ func (b *BaseApi) OperateTool(c *gin.Context) {
|
|||||||
// @Summary Get tool config
|
// @Summary Get tool config
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body request.HostToolConfig true "request"
|
// @Param request body request.HostToolConfig true "request"
|
||||||
// @Success 200
|
// @Success 200 {object} response.HostToolConfig
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /host/tool/config [post]
|
// @Router /hosts/tool/config [post]
|
||||||
// @x-panel-log {"bodyKeys":["operate"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"[operate] 主机工具配置文件 ","formatEN":"[operate] tool config"}
|
// @x-panel-log {"bodyKeys":["operate"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"[operate] 主机工具配置文件 ","formatEN":"[operate] tool config"}
|
||||||
func (b *BaseApi) OperateToolConfig(c *gin.Context) {
|
func (b *BaseApi) OperateToolConfig(c *gin.Context) {
|
||||||
var req request.HostToolConfig
|
var req request.HostToolConfig
|
||||||
@@ -100,10 +100,10 @@ func (b *BaseApi) OperateToolConfig(c *gin.Context) {
|
|||||||
// @Summary Get tool logs
|
// @Summary Get tool logs
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body request.HostToolLogReq true "request"
|
// @Param request body request.HostToolLogReq true "request"
|
||||||
// @Success 200
|
// @Success 200 {string} logContent
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /host/tool/log [post]
|
// @Router /hosts/tool/log [post]
|
||||||
func (b *BaseApi) GetToolLog(c *gin.Context) {
|
func (b *BaseApi) GetToolLog(c *gin.Context) {
|
||||||
var req request.HostToolLogReq
|
var req request.HostToolLogReq
|
||||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||||
@@ -125,7 +125,7 @@ func (b *BaseApi) GetToolLog(c *gin.Context) {
|
|||||||
// @Success 200
|
// @Success 200
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /host/tool/supervisor/process [post]
|
// @Router /hosts/tool/supervisor/process [post]
|
||||||
// @x-panel-log {"bodyKeys":["operate"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"[operate] 守护进程 ","formatEN":"[operate] process"}
|
// @x-panel-log {"bodyKeys":["operate"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"[operate] 守护进程 ","formatEN":"[operate] process"}
|
||||||
func (b *BaseApi) OperateProcess(c *gin.Context) {
|
func (b *BaseApi) OperateProcess(c *gin.Context) {
|
||||||
var req request.SupervisorProcessConfig
|
var req request.SupervisorProcessConfig
|
||||||
@@ -144,10 +144,10 @@ func (b *BaseApi) OperateProcess(c *gin.Context) {
|
|||||||
// @Tags Host tool
|
// @Tags Host tool
|
||||||
// @Summary Get Supervisor process config
|
// @Summary Get Supervisor process config
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Success 200
|
// @Success 200 {object} response.SupervisorProcessConfig
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /host/tool/supervisor/process [get]
|
// @Router /hosts/tool/supervisor/process [get]
|
||||||
func (b *BaseApi) GetProcess(c *gin.Context) {
|
func (b *BaseApi) GetProcess(c *gin.Context) {
|
||||||
configs, err := hostToolService.GetSupervisorProcessConfig()
|
configs, err := hostToolService.GetSupervisorProcessConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -161,10 +161,10 @@ func (b *BaseApi) GetProcess(c *gin.Context) {
|
|||||||
// @Summary Get Supervisor process config
|
// @Summary Get Supervisor process config
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body request.SupervisorProcessFileReq true "request"
|
// @Param request body request.SupervisorProcessFileReq true "request"
|
||||||
// @Success 200
|
// @Success 200 {string} content
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /host/tool/supervisor/process/file [post]
|
// @Router /hosts/tool/supervisor/process/file [post]
|
||||||
// @x-panel-log {"bodyKeys":["operate"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"[operate] Supervisor 进程文件 ","formatEN":"[operate] Supervisor Process Config file"}
|
// @x-panel-log {"bodyKeys":["operate"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"[operate] Supervisor 进程文件 ","formatEN":"[operate] Supervisor Process Config file"}
|
||||||
func (b *BaseApi) GetProcessFile(c *gin.Context) {
|
func (b *BaseApi) GetProcessFile(c *gin.Context) {
|
||||||
var req request.SupervisorProcessFileReq
|
var req request.SupervisorProcessFileReq
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ func (b *BaseApi) ImageBuild(c *gin.Context) {
|
|||||||
// @Summary Pull image
|
// @Summary Pull image
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body dto.ImagePull true "request"
|
// @Param request body dto.ImagePull true "request"
|
||||||
// @Success 200 {string} log
|
// @Success 200 {string} logPath
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /containers/image/pull [post]
|
// @Router /containers/image/pull [post]
|
||||||
@@ -118,7 +118,7 @@ func (b *BaseApi) ImagePull(c *gin.Context) {
|
|||||||
// @Summary Push image
|
// @Summary Push image
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body dto.ImagePush true "request"
|
// @Param request body dto.ImagePush true "request"
|
||||||
// @Success 200 {string} log
|
// @Success 200 {string} logPath
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /containers/image/push [post]
|
// @Router /containers/image/push [post]
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ func (b *BaseApi) CheckRepoStatus(c *gin.Context) {
|
|||||||
// @Tags Container Image-repo
|
// @Tags Container Image-repo
|
||||||
// @Summary Create image repo
|
// @Summary Create image repo
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body dto.ImageRepoDelete true "request"
|
// @Param request body dto.ImageRepoCreate true "request"
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200
|
// @Success 200
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
@@ -99,20 +99,20 @@ func (b *BaseApi) CreateRepo(c *gin.Context) {
|
|||||||
// @Tags Container Image-repo
|
// @Tags Container Image-repo
|
||||||
// @Summary Delete image repo
|
// @Summary Delete image repo
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body dto.ImageRepoDelete true "request"
|
// @Param request body dto.OperateByID true "request"
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200
|
// @Success 200
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /containers/repo/del [post]
|
// @Router /containers/repo/del [post]
|
||||||
// @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"ids","isList":true,"db":"image_repos","output_column":"name","output_value":"names"}],"formatZH":"删除镜像仓库 [names]","formatEN":"delete image repo [names]"}
|
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":false,"db":"image_repos","output_column":"name","output_value":"name"}],"formatZH":"删除镜像仓库 [name]","formatEN":"delete image repo [name]"}
|
||||||
func (b *BaseApi) DeleteRepo(c *gin.Context) {
|
func (b *BaseApi) DeleteRepo(c *gin.Context) {
|
||||||
var req dto.ImageRepoDelete
|
var req dto.OperateByID
|
||||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := imageRepoService.BatchDelete(req); err != nil {
|
if err := imageRepoService.Delete(req); err != nil {
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ func (b *BaseApi) GetLoginLogs(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
total, list, err := logService.PageLoginLog(req)
|
total, list, err := logService.PageLoginLog(c, req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
return
|
return
|
||||||
@@ -63,7 +63,7 @@ func (b *BaseApi) GetOperationLogs(c *gin.Context) {
|
|||||||
// @Summary Clean operation logs
|
// @Summary Clean operation logs
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body dto.CleanLog true "request"
|
// @Param request body dto.CleanLog true "request"
|
||||||
// @Success 200 {object} dto.PageResult
|
// @Success 200
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /logs/clean [post]
|
// @Router /logs/clean [post]
|
||||||
@@ -84,7 +84,7 @@ func (b *BaseApi) CleanLogs(c *gin.Context) {
|
|||||||
|
|
||||||
// @Tags Logs
|
// @Tags Logs
|
||||||
// @Summary Load system log files
|
// @Summary Load system log files
|
||||||
// @Success 200
|
// @Success 200 {array} string
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /logs/system/files [get]
|
// @Router /logs/system/files [get]
|
||||||
@@ -100,7 +100,7 @@ func (b *BaseApi) GetSystemFiles(c *gin.Context) {
|
|||||||
|
|
||||||
// @Tags Logs
|
// @Tags Logs
|
||||||
// @Summary Load system logs
|
// @Summary Load system logs
|
||||||
// @Success 200
|
// @Success 200 {string} data
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /logs/system [post]
|
// @Router /logs/system [post]
|
||||||
|
|||||||
@@ -0,0 +1,167 @@
|
|||||||
|
package v1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
// @Tags McpServer
|
||||||
|
// @Summary List mcp servers
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body request.McpServerSearch true "request"
|
||||||
|
// @Success 200 {object} response.McpServersRes
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Security Timestamp
|
||||||
|
// @Router /mcp/search [post]
|
||||||
|
func (b *BaseApi) PageMcpServers(c *gin.Context) {
|
||||||
|
var req request.McpServerSearch
|
||||||
|
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
list := mcpServerService.Page(req)
|
||||||
|
helper.SuccessWithData(c, list)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags McpServer
|
||||||
|
// @Summary Create mcp server
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body request.McpServerCreate true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Security Timestamp
|
||||||
|
// @Router /mcp/server [post]
|
||||||
|
func (b *BaseApi) CreateMcpServer(c *gin.Context) {
|
||||||
|
var req request.McpServerCreate
|
||||||
|
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err := mcpServerService.Create(req)
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithOutData(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags McpServer
|
||||||
|
// @Summary Update mcp server
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body request.McpServerUpdate true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Security Timestamp
|
||||||
|
// @Router /mcp/server/update [post]
|
||||||
|
func (b *BaseApi) UpdateMcpServer(c *gin.Context) {
|
||||||
|
var req request.McpServerUpdate
|
||||||
|
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err := mcpServerService.Update(req)
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithOutData(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags McpServer
|
||||||
|
// @Summary Delete mcp server
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body request.McpServerDelete true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Security Timestamp
|
||||||
|
// @Router /mcp/server/del [post]
|
||||||
|
func (b *BaseApi) DeleteMcpServer(c *gin.Context) {
|
||||||
|
var req request.McpServerDelete
|
||||||
|
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err := mcpServerService.Delete(req.ID)
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithOutData(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags McpServer
|
||||||
|
// @Summary Operate mcp server
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body request.McpServerOperate true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Security Timestamp
|
||||||
|
// @Router /mcp/server/op [post]
|
||||||
|
func (b *BaseApi) OperateMcpServer(c *gin.Context) {
|
||||||
|
var req request.McpServerOperate
|
||||||
|
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err := mcpServerService.Operate(req)
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithOutData(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags McpServer
|
||||||
|
// @Summary Bind Domain for mcp server
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body request.McpBindDomain true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Security Timestamp
|
||||||
|
// @Router /mcp/domain/bind [post]
|
||||||
|
func (b *BaseApi) BindMcpDomain(c *gin.Context) {
|
||||||
|
var req request.McpBindDomain
|
||||||
|
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err := mcpServerService.BindDomain(req)
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithOutData(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags McpServer
|
||||||
|
// @Summary Update bind Domain for mcp server
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body request.McpBindDomainUpdate true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Security Timestamp
|
||||||
|
// @Router /mcp/domain/update [post]
|
||||||
|
func (b *BaseApi) UpdateMcpBindDomain(c *gin.Context) {
|
||||||
|
var req request.McpBindDomainUpdate
|
||||||
|
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err := mcpServerService.UpdateBindDomain(req)
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithOutData(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags McpServer
|
||||||
|
// @Summary Get bin Domain for mcp server
|
||||||
|
// @Accept json
|
||||||
|
// @Success 200 {object} response.McpBindDomainRes
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Security Timestamp
|
||||||
|
// @Router /mcp/domain/get [get]
|
||||||
|
func (b *BaseApi) GetMcpBindDomain(c *gin.Context) {
|
||||||
|
res, err := mcpServerService.GetBindDomain()
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, res)
|
||||||
|
}
|
||||||
@@ -18,7 +18,7 @@ import (
|
|||||||
// @Tags Monitor
|
// @Tags Monitor
|
||||||
// @Summary Load monitor datas
|
// @Summary Load monitor datas
|
||||||
// @Param request body dto.MonitorSearch true "request"
|
// @Param request body dto.MonitorSearch true "request"
|
||||||
// @Success 200
|
// @Success 200 {array} dto.MonitorData
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /hosts/monitor/search [post]
|
// @Router /hosts/monitor/search [post]
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
|
|
||||||
// @Tags OpenResty
|
// @Tags OpenResty
|
||||||
// @Summary Load OpenResty conf
|
// @Summary Load OpenResty conf
|
||||||
// @Success 200 {object} response.FileInfo
|
// @Success 200 {object} response.NginxFile
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /openresty [get]
|
// @Router /openresty [get]
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import (
|
|||||||
// @Summary Page Extensions
|
// @Summary Page Extensions
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body request.PHPExtensionsSearch true "request"
|
// @Param request body request.PHPExtensionsSearch true "request"
|
||||||
// @Success 200 {array} response.PHPExtensionsDTO
|
// @Success 200 {object} dto.PageResult
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /runtimes/php/extensions/search [post]
|
// @Router /runtimes/php/extensions/search [post]
|
||||||
@@ -27,7 +27,10 @@ func (b *BaseApi) PagePHPExtensions(c *gin.Context) {
|
|||||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
helper.SuccessWithData(c, list)
|
helper.SuccessWithData(c, dto.PageResult{
|
||||||
|
Total: int64(len(list)),
|
||||||
|
Items: list,
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
total, list, err := phpExtensionsService.Page(req)
|
total, list, err := phpExtensionsService.Page(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import (
|
|||||||
// @Summary List Recycle Bin files
|
// @Summary List Recycle Bin files
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body dto.PageInfo true "request"
|
// @Param request body dto.PageInfo true "request"
|
||||||
// @Success 200
|
// @Success 200 {object} dto.PageResult
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /files/recycle/search [post]
|
// @Router /files/recycle/search [post]
|
||||||
@@ -72,7 +72,7 @@ func (b *BaseApi) ClearRecycleBinFile(c *gin.Context) {
|
|||||||
// @Tags File
|
// @Tags File
|
||||||
// @Summary Get Recycle Bin status
|
// @Summary Get Recycle Bin status
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Success 200
|
// @Success 200 {string} content
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /files/recycle/status [get]
|
// @Router /files/recycle/status [get]
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import (
|
|||||||
// @Summary List runtimes
|
// @Summary List runtimes
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body request.RuntimeSearch true "request"
|
// @Param request body request.RuntimeSearch true "request"
|
||||||
// @Success 200
|
// @Success 200 {object} dto.PageResult
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /runtimes/search [post]
|
// @Router /runtimes/search [post]
|
||||||
@@ -36,7 +36,7 @@ func (b *BaseApi) SearchRuntimes(c *gin.Context) {
|
|||||||
// @Summary Create runtime
|
// @Summary Create runtime
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body request.RuntimeCreate true "request"
|
// @Param request body request.RuntimeCreate true "request"
|
||||||
// @Success 200
|
// @Success 200 {object} model.Runtime
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /runtimes [post]
|
// @Router /runtimes [post]
|
||||||
@@ -115,10 +115,10 @@ func (b *BaseApi) UpdateRuntime(c *gin.Context) {
|
|||||||
// @Summary Get runtime
|
// @Summary Get runtime
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param id path string true "request"
|
// @Param id path string true "request"
|
||||||
// @Success 200
|
// @Success 200 {object} response.RuntimeDTO
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /runtimes/:id [get]
|
// @Router /runtimes/{id} [get]
|
||||||
func (b *BaseApi) GetRuntime(c *gin.Context) {
|
func (b *BaseApi) GetRuntime(c *gin.Context) {
|
||||||
id, err := helper.GetIntParamByKey(c, "id")
|
id, err := helper.GetIntParamByKey(c, "id")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -137,7 +137,7 @@ func (b *BaseApi) GetRuntime(c *gin.Context) {
|
|||||||
// @Summary Get Node package scripts
|
// @Summary Get Node package scripts
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body request.NodePackageReq true "request"
|
// @Param request body request.NodePackageReq true "request"
|
||||||
// @Success 200
|
// @Success 200 {array} response.PackageScripts
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /runtimes/node/package [post]
|
// @Router /runtimes/node/package [post]
|
||||||
@@ -180,7 +180,7 @@ func (b *BaseApi) OperateRuntime(c *gin.Context) {
|
|||||||
// @Summary Get Node modules
|
// @Summary Get Node modules
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body request.NodeModuleReq true "request"
|
// @Param request body request.NodeModuleReq true "request"
|
||||||
// @Success 200
|
// @Success 200 {array} response.NodeModule
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /runtimes/node/modules [post]
|
// @Router /runtimes/node/modules [post]
|
||||||
|
|||||||
@@ -3,8 +3,10 @@ package v1
|
|||||||
import (
|
import (
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
"regexp"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||||
@@ -53,11 +55,21 @@ func (b *BaseApi) UpdateSetting(c *gin.Context) {
|
|||||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if req.Key == "SecurityEntrance" {
|
||||||
|
if !checkEntrancePattern(req.Value) {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, fmt.Errorf("the format of the security entrance %s is incorrect.", req.Value))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if err := settingService.Update(req.Key, req.Value); err != nil {
|
if err := settingService.Update(req.Key, req.Value); err != nil {
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if req.Key == "SecurityEntrance" {
|
||||||
|
entranceValue := base64.StdEncoding.EncodeToString([]byte(req.Value))
|
||||||
|
c.SetCookie("SecurityEntrance", entranceValue, 0, "", "", false, true)
|
||||||
|
}
|
||||||
helper.SuccessWithData(c, nil)
|
helper.SuccessWithData(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,7 +172,7 @@ func (b *BaseApi) UpdateSSL(c *gin.Context) {
|
|||||||
|
|
||||||
// @Tags System Setting
|
// @Tags System Setting
|
||||||
// @Summary Load system cert info
|
// @Summary Load system cert info
|
||||||
// @Success 200 {object} dto.SettingInfo
|
// @Success 200 {object} dto.SSLInfo
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /settings/ssl/info [get]
|
// @Router /settings/ssl/info [get]
|
||||||
@@ -192,7 +204,7 @@ func (b *BaseApi) DownloadSSL(c *gin.Context) {
|
|||||||
// @Tags System Setting
|
// @Tags System Setting
|
||||||
// @Summary Load system address
|
// @Summary Load system address
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Success 200
|
// @Success 200 {array} string
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /settings/interface [get]
|
// @Router /settings/interface [get]
|
||||||
@@ -346,7 +358,7 @@ func (b *BaseApi) MFABind(c *gin.Context) {
|
|||||||
// @Tags System Setting
|
// @Tags System Setting
|
||||||
// @Summary Generate api key
|
// @Summary Generate api key
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Success 200
|
// @Success 200 {string} apiKey
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /settings/api/config/generate/key [post]
|
// @Router /settings/api/config/generate/key [post]
|
||||||
@@ -391,3 +403,11 @@ func (b *BaseApi) UpdateApiConfig(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
helper.SuccessWithData(c, nil)
|
helper.SuccessWithData(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func checkEntrancePattern(val string) bool {
|
||||||
|
if len(val) == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
result, _ := regexp.MatchString("^[a-zA-Z0-9]{5,116}$", val)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ func (b *BaseApi) ImportSnapshot(c *gin.Context) {
|
|||||||
// @Summary Load Snapshot status
|
// @Summary Load Snapshot status
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body dto.OperateByID true "request"
|
// @Param request body dto.OperateByID true "request"
|
||||||
// @Success 200
|
// @Success 200 {object} dto.SnapshotStatus
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /settings/snapshot/status [post]
|
// @Router /settings/snapshot/status [post]
|
||||||
@@ -124,7 +124,7 @@ func (b *BaseApi) SearchSnapshot(c *gin.Context) {
|
|||||||
// @Summary Load system snapshot size
|
// @Summary Load system snapshot size
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body dto.PageSnapshot true "request"
|
// @Param request body dto.PageSnapshot true "request"
|
||||||
// @Success 200
|
// @Success 200 {array} dto.SnapshotFile
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /settings/snapshot/size [post]
|
// @Router /settings/snapshot/size [post]
|
||||||
|
|||||||
+11
-10
@@ -12,7 +12,7 @@ import (
|
|||||||
// @Success 200 {object} dto.SSHInfo
|
// @Success 200 {object} dto.SSHInfo
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /host/ssh/search [post]
|
// @Router /hosts/ssh/search [post]
|
||||||
func (b *BaseApi) GetSSHInfo(c *gin.Context) {
|
func (b *BaseApi) GetSSHInfo(c *gin.Context) {
|
||||||
info, err := sshService.GetSSHInfo()
|
info, err := sshService.GetSSHInfo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -26,9 +26,10 @@ func (b *BaseApi) GetSSHInfo(c *gin.Context) {
|
|||||||
// @Summary Operate SSH
|
// @Summary Operate SSH
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body dto.Operate true "request"
|
// @Param request body dto.Operate true "request"
|
||||||
|
// @Success 200
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /host/ssh/operate [post]
|
// @Router /hosts/ssh/operate [post]
|
||||||
// @x-panel-log {"bodyKeys":["operation"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"[operation] SSH ","formatEN":"[operation] SSH"}
|
// @x-panel-log {"bodyKeys":["operation"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"[operation] SSH ","formatEN":"[operation] SSH"}
|
||||||
func (b *BaseApi) OperateSSH(c *gin.Context) {
|
func (b *BaseApi) OperateSSH(c *gin.Context) {
|
||||||
var req dto.Operate
|
var req dto.Operate
|
||||||
@@ -50,7 +51,7 @@ func (b *BaseApi) OperateSSH(c *gin.Context) {
|
|||||||
// @Success 200
|
// @Success 200
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /host/ssh/update [post]
|
// @Router /hosts/ssh/update [post]
|
||||||
// @x-panel-log {"bodyKeys":["key","value"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"修改 SSH 配置 [key] => [value]","formatEN":"update SSH setting [key] => [value]"}
|
// @x-panel-log {"bodyKeys":["key","value"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"修改 SSH 配置 [key] => [value]","formatEN":"update SSH setting [key] => [value]"}
|
||||||
func (b *BaseApi) UpdateSSH(c *gin.Context) {
|
func (b *BaseApi) UpdateSSH(c *gin.Context) {
|
||||||
var req dto.SSHUpdate
|
var req dto.SSHUpdate
|
||||||
@@ -72,7 +73,7 @@ func (b *BaseApi) UpdateSSH(c *gin.Context) {
|
|||||||
// @Success 200
|
// @Success 200
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /host/conffile/update [post]
|
// @Router /hosts/conffile/update [post]
|
||||||
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"修改 SSH 配置文件","formatEN":"update SSH conf"}
|
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"修改 SSH 配置文件","formatEN":"update SSH conf"}
|
||||||
func (b *BaseApi) UpdateSSHByfile(c *gin.Context) {
|
func (b *BaseApi) UpdateSSHByfile(c *gin.Context) {
|
||||||
var req dto.SSHConf
|
var req dto.SSHConf
|
||||||
@@ -94,7 +95,7 @@ func (b *BaseApi) UpdateSSHByfile(c *gin.Context) {
|
|||||||
// @Success 200
|
// @Success 200
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /host/ssh/generate [post]
|
// @Router /hosts/ssh/generate [post]
|
||||||
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"生成 SSH 密钥 ","formatEN":"generate SSH secret"}
|
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"生成 SSH 密钥 ","formatEN":"generate SSH secret"}
|
||||||
func (b *BaseApi) GenerateSSH(c *gin.Context) {
|
func (b *BaseApi) GenerateSSH(c *gin.Context) {
|
||||||
var req dto.GenerateSSH
|
var req dto.GenerateSSH
|
||||||
@@ -113,10 +114,10 @@ func (b *BaseApi) GenerateSSH(c *gin.Context) {
|
|||||||
// @Summary Load host SSH secret
|
// @Summary Load host SSH secret
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body dto.GenerateLoad true "request"
|
// @Param request body dto.GenerateLoad true "request"
|
||||||
// @Success 200
|
// @Success 200 {string} data
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /host/ssh/secret [post]
|
// @Router /hosts/ssh/secret [post]
|
||||||
func (b *BaseApi) LoadSSHSecret(c *gin.Context) {
|
func (b *BaseApi) LoadSSHSecret(c *gin.Context) {
|
||||||
var req dto.GenerateLoad
|
var req dto.GenerateLoad
|
||||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||||
@@ -138,7 +139,7 @@ func (b *BaseApi) LoadSSHSecret(c *gin.Context) {
|
|||||||
// @Success 200 {object} dto.SSHLog
|
// @Success 200 {object} dto.SSHLog
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /host/ssh/log [post]
|
// @Router /hosts/ssh/log [post]
|
||||||
func (b *BaseApi) LoadSSHLogs(c *gin.Context) {
|
func (b *BaseApi) LoadSSHLogs(c *gin.Context) {
|
||||||
var req dto.SearchSSHLog
|
var req dto.SearchSSHLog
|
||||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||||
@@ -155,10 +156,10 @@ func (b *BaseApi) LoadSSHLogs(c *gin.Context) {
|
|||||||
|
|
||||||
// @Tags SSH
|
// @Tags SSH
|
||||||
// @Summary Load host SSH conf
|
// @Summary Load host SSH conf
|
||||||
// @Success 200
|
// @Success 200 {string} data
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /host/ssh/conf [get]
|
// @Router /hosts/ssh/conf [get]
|
||||||
func (b *BaseApi) LoadSSHConf(c *gin.Context) {
|
func (b *BaseApi) LoadSSHConf(c *gin.Context) {
|
||||||
data, err := sshService.LoadSSHConf()
|
data, err := sshService.LoadSSHConf()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -68,12 +68,11 @@ func (b *BaseApi) WsSsh(c *gin.Context) {
|
|||||||
|
|
||||||
<-quitChan
|
<-quitChan
|
||||||
|
|
||||||
if wshandleError(wsConn, err) {
|
dt := time.Now().Add(time.Second)
|
||||||
return
|
_ = wsConn.WriteControl(websocket.CloseMessage, nil, dt)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *BaseApi) RedisWsSsh(c *gin.Context) {
|
func (b *BaseApi) ContainerWsSSH(c *gin.Context) {
|
||||||
wsConn, err := upGrader.Upgrade(c.Writer, c.Request, nil)
|
wsConn, err := upGrader.Upgrade(c.Writer, c.Request, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
global.LOG.Errorf("gin context http handler failed, err: %v", err)
|
global.LOG.Errorf("gin context http handler failed, err: %v", err)
|
||||||
@@ -95,38 +94,30 @@ func (b *BaseApi) RedisWsSsh(c *gin.Context) {
|
|||||||
if wshandleError(wsConn, errors.WithMessage(err, "invalid param rows in request")) {
|
if wshandleError(wsConn, errors.WithMessage(err, "invalid param rows in request")) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
name := c.Query("name")
|
source := c.Query("source")
|
||||||
from := c.Query("from")
|
var containerID string
|
||||||
commands := []string{"redis-cli"}
|
var initCmd []string
|
||||||
database, err := databaseService.Get(name)
|
switch source {
|
||||||
if wshandleError(wsConn, errors.WithMessage(err, "no such database in db")) {
|
case "redis":
|
||||||
return
|
containerID, initCmd, err = loadRedisInitCmd(c)
|
||||||
}
|
case "ollama":
|
||||||
if from == "local" {
|
containerID, initCmd, err = loadOllamaInitCmd(c)
|
||||||
redisInfo, err := appInstallService.LoadConnInfo(dto.OperationWithNameAndType{Name: name, Type: "redis"})
|
case "container":
|
||||||
if wshandleError(wsConn, errors.WithMessage(err, "no such database in db")) {
|
containerID, initCmd, err = loadContainerInitCmd(c)
|
||||||
|
default:
|
||||||
|
if wshandleError(wsConn, fmt.Errorf("not support such source %s", source)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
name = redisInfo.ContainerName
|
|
||||||
if len(database.Password) != 0 {
|
|
||||||
commands = []string{"redis-cli", "-a", database.Password, "--no-auth-warning"}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
itemPort := fmt.Sprintf("%v", database.Port)
|
|
||||||
commands = []string{"redis-cli", "-h", database.Address, "-p", itemPort}
|
|
||||||
if len(database.Password) != 0 {
|
|
||||||
commands = []string{"redis-cli", "-h", database.Address, "-p", itemPort, "-a", database.Password, "--no-auth-warning"}
|
|
||||||
}
|
|
||||||
name = "1Panel-redis-cli-tools"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pidMap := loadMapFromDockerTop(name)
|
|
||||||
itemCmds := append([]string{"exec", "-it", name}, commands...)
|
|
||||||
slave, err := terminal.NewCommand(itemCmds)
|
|
||||||
if wshandleError(wsConn, err) {
|
if wshandleError(wsConn, err) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer killBash(name, strings.Join(commands, " "), pidMap)
|
pidMap := loadMapFromDockerTop(containerID)
|
||||||
|
slave, err := terminal.NewCommand(initCmd)
|
||||||
|
if wshandleError(wsConn, err) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer killBash(containerID, strings.ReplaceAll(strings.Join(initCmd, " "), fmt.Sprintf("exec -it %s ", containerID), ""), pidMap)
|
||||||
defer slave.Close()
|
defer slave.Close()
|
||||||
|
|
||||||
tty, err := terminal.NewLocalWsSession(cols, rows, wsConn, slave, false)
|
tty, err := terminal.NewLocalWsSession(cols, rows, wsConn, slave, false)
|
||||||
@@ -141,83 +132,68 @@ func (b *BaseApi) RedisWsSsh(c *gin.Context) {
|
|||||||
<-quitChan
|
<-quitChan
|
||||||
|
|
||||||
global.LOG.Info("websocket finished")
|
global.LOG.Info("websocket finished")
|
||||||
if wshandleError(wsConn, err) {
|
dt := time.Now().Add(time.Second)
|
||||||
return
|
_ = wsConn.WriteControl(websocket.CloseMessage, nil, dt)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *BaseApi) ContainerWsSsh(c *gin.Context) {
|
func loadRedisInitCmd(c *gin.Context) (string, []string, error) {
|
||||||
wsConn, err := upGrader.Upgrade(c.Writer, c.Request, nil)
|
name := c.Query("name")
|
||||||
|
from := c.Query("from")
|
||||||
|
commands := []string{"exec", "-it"}
|
||||||
|
database, err := databaseService.Get(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
global.LOG.Errorf("gin context http handler failed, err: %v", err)
|
return "", nil, fmt.Errorf("no such database in db, err: %v", err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
defer wsConn.Close()
|
if from == "local" {
|
||||||
|
redisInfo, err := appInstallService.LoadConnInfo(dto.OperationWithNameAndType{Name: name, Type: "redis"})
|
||||||
if global.CONF.System.IsDemo {
|
if err != nil {
|
||||||
if wshandleError(wsConn, errors.New(" demo server, prohibit this operation!")) {
|
return "", nil, fmt.Errorf("no such app in db, err: %v", err)
|
||||||
return
|
}
|
||||||
|
name = redisInfo.ContainerName
|
||||||
|
commands = append(commands, []string{name, "redis-cli"}...)
|
||||||
|
if len(database.Password) != 0 {
|
||||||
|
commands = append(commands, []string{"-a", database.Password, "--no-auth-warning"}...)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
name = "1Panel-redis-cli-tools"
|
||||||
|
commands = append(commands, []string{name, "redis-cli", "-h", database.Address, "-p", fmt.Sprintf("%v", database.Port)}...)
|
||||||
|
if len(database.Password) != 0 {
|
||||||
|
commands = append(commands, []string{"-a", database.Password, "--no-auth-warning"}...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return name, commands, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadOllamaInitCmd(c *gin.Context) (string, []string, error) {
|
||||||
|
name := c.Query("name")
|
||||||
|
if cmd.CheckIllegal(name) {
|
||||||
|
return "", nil, fmt.Errorf("ollama model %s contains illegal characters", name)
|
||||||
|
}
|
||||||
|
ollamaInfo, err := appInstallService.LoadConnInfo(dto.OperationWithNameAndType{Name: "", Type: "ollama"})
|
||||||
|
if err != nil {
|
||||||
|
return "", nil, fmt.Errorf("no such app in db, err: %v", err)
|
||||||
|
}
|
||||||
|
containerName := ollamaInfo.ContainerName
|
||||||
|
return containerName, []string{"exec", "-it", containerName, "ollama", "run", name}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadContainerInitCmd(c *gin.Context) (string, []string, error) {
|
||||||
containerID := c.Query("containerid")
|
containerID := c.Query("containerid")
|
||||||
command := c.Query("command")
|
command := c.Query("command")
|
||||||
user := c.Query("user")
|
user := c.Query("user")
|
||||||
if len(command) == 0 || len(containerID) == 0 {
|
|
||||||
if wshandleError(wsConn, errors.New("error param of command or containerID")) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cols, err := strconv.Atoi(c.DefaultQuery("cols", "80"))
|
|
||||||
if wshandleError(wsConn, errors.WithMessage(err, "invalid param cols in request")) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
rows, err := strconv.Atoi(c.DefaultQuery("rows", "40"))
|
|
||||||
if wshandleError(wsConn, errors.WithMessage(err, "invalid param rows in request")) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
cmds := []string{"exec", containerID, command}
|
|
||||||
if len(user) != 0 {
|
|
||||||
cmds = []string{"exec", "-u", user, containerID, command}
|
|
||||||
}
|
|
||||||
if cmd.CheckIllegal(user, containerID, command) {
|
if cmd.CheckIllegal(user, containerID, command) {
|
||||||
if wshandleError(wsConn, errors.New(" The command contains illegal characters.")) {
|
return "", nil, fmt.Errorf("the command contains illegal characters. command: %s, user: %s, containerID: %s", command, user, containerID)
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
stdout, err := cmd.ExecWithCheck("docker", cmds...)
|
if len(command) == 0 || len(containerID) == 0 {
|
||||||
if wshandleError(wsConn, errors.WithMessage(err, stdout)) {
|
return "", nil, fmt.Errorf("error param of command: %s or containerID: %s", command, containerID)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
commands := []string{"exec", "-it", containerID, command}
|
commands := []string{"exec", "-it", containerID, command}
|
||||||
if len(user) != 0 {
|
if len(user) != 0 {
|
||||||
commands = []string{"exec", "-it", "-u", user, containerID, command}
|
commands = []string{"exec", "-it", "-u", user, containerID, command}
|
||||||
}
|
}
|
||||||
pidMap := loadMapFromDockerTop(containerID)
|
|
||||||
slave, err := terminal.NewCommand(commands)
|
|
||||||
if wshandleError(wsConn, err) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer killBash(containerID, command, pidMap)
|
|
||||||
defer slave.Close()
|
|
||||||
|
|
||||||
tty, err := terminal.NewLocalWsSession(cols, rows, wsConn, slave, true)
|
return containerID, commands, nil
|
||||||
if wshandleError(wsConn, err) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
quitChan := make(chan bool, 3)
|
|
||||||
tty.Start(quitChan)
|
|
||||||
go slave.Wait(quitChan)
|
|
||||||
|
|
||||||
<-quitChan
|
|
||||||
|
|
||||||
global.LOG.Info("websocket finished")
|
|
||||||
if wshandleError(wsConn, err) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func wshandleError(ws *websocket.Conn, err error) bool {
|
func wshandleError(ws *websocket.Conn, err error) bool {
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ func (b *BaseApi) GetUpgradeInfo(c *gin.Context) {
|
|||||||
// @Summary Load release notes by version
|
// @Summary Load release notes by version
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body dto.Upgrade true "request"
|
// @Param request body dto.Upgrade true "request"
|
||||||
// @Success 200
|
// @Success 200 {string} notes
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /settings/upgrade [get]
|
// @Router /settings/upgrade [get]
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ func (b *BaseApi) GetWebsites(c *gin.Context) {
|
|||||||
|
|
||||||
// @Tags Website
|
// @Tags Website
|
||||||
// @Summary List website names
|
// @Summary List website names
|
||||||
// @Success 200 {array} string
|
// @Success 200 {array} response.WebsiteOption
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /websites/options [get]
|
// @Router /websites/options [get]
|
||||||
@@ -166,7 +166,7 @@ func (b *BaseApi) UpdateWebsite(c *gin.Context) {
|
|||||||
// @Success 200 {object} response.WebsiteDTO
|
// @Success 200 {object} response.WebsiteDTO
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /websites/:id [get]
|
// @Router /websites/{id} [get]
|
||||||
func (b *BaseApi) GetWebsite(c *gin.Context) {
|
func (b *BaseApi) GetWebsite(c *gin.Context) {
|
||||||
id, err := helper.GetParamID(c)
|
id, err := helper.GetParamID(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -185,10 +185,11 @@ func (b *BaseApi) GetWebsite(c *gin.Context) {
|
|||||||
// @Summary Search website nginx by id
|
// @Summary Search website nginx by id
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param id path integer true "request"
|
// @Param id path integer true "request"
|
||||||
|
// @Param type path string true "type"
|
||||||
// @Success 200 {object} response.FileInfo
|
// @Success 200 {object} response.FileInfo
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /websites/:id/config/:type [get]
|
// @Router /websites/{id}/config/{type} [get]
|
||||||
func (b *BaseApi) GetWebsiteNginx(c *gin.Context) {
|
func (b *BaseApi) GetWebsiteNginx(c *gin.Context) {
|
||||||
id, err := helper.GetParamID(c)
|
id, err := helper.GetParamID(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -254,7 +255,7 @@ func (b *BaseApi) UpdateNginxConfig(c *gin.Context) {
|
|||||||
// @Success 200 {object} response.WebsiteHTTPS
|
// @Success 200 {object} response.WebsiteHTTPS
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /websites/:id/https [get]
|
// @Router /websites/{id}/https [get]
|
||||||
func (b *BaseApi) GetHTTPSConfig(c *gin.Context) {
|
func (b *BaseApi) GetHTTPSConfig(c *gin.Context) {
|
||||||
id, err := helper.GetParamID(c)
|
id, err := helper.GetParamID(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -272,11 +273,12 @@ func (b *BaseApi) GetHTTPSConfig(c *gin.Context) {
|
|||||||
// @Tags Website HTTPS
|
// @Tags Website HTTPS
|
||||||
// @Summary Update https conf
|
// @Summary Update https conf
|
||||||
// @Accept json
|
// @Accept json
|
||||||
|
// @Param id path integer true "request"
|
||||||
// @Param request body request.WebsiteHTTPSOp true "request"
|
// @Param request body request.WebsiteHTTPSOp true "request"
|
||||||
// @Success 200 {object} response.WebsiteHTTPS
|
// @Success 200 {object} response.WebsiteHTTPS
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /websites/:id/https [post]
|
// @Router /websites/{id}/https [post]
|
||||||
// @x-panel-log {"bodyKeys":["websiteId"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"websiteId","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"更新网站 [domain] https 配置","formatEN":"Update website https [domain] conf"}
|
// @x-panel-log {"bodyKeys":["websiteId"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"websiteId","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"更新网站 [domain] https 配置","formatEN":"Update website https [domain] conf"}
|
||||||
func (b *BaseApi) UpdateHTTPSConfig(c *gin.Context) {
|
func (b *BaseApi) UpdateHTTPSConfig(c *gin.Context) {
|
||||||
var req request.WebsiteHTTPSOp
|
var req request.WebsiteHTTPSOp
|
||||||
@@ -386,7 +388,7 @@ func (b *BaseApi) ChangeDefaultServer(c *gin.Context) {
|
|||||||
// @Success 200 {object} response.PHPConfig
|
// @Success 200 {object} response.PHPConfig
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /websites/php/config/:id [get]
|
// @Router /websites/php/config/{id} [get]
|
||||||
func (b *BaseApi) GetWebsitePHPConfig(c *gin.Context) {
|
func (b *BaseApi) GetWebsitePHPConfig(c *gin.Context) {
|
||||||
id, err := helper.GetParamID(c)
|
id, err := helper.GetParamID(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -468,7 +470,7 @@ func (b *BaseApi) ChangePHPVersion(c *gin.Context) {
|
|||||||
// @Summary Get rewrite conf
|
// @Summary Get rewrite conf
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body request.NginxRewriteReq true "request"
|
// @Param request body request.NginxRewriteReq true "request"
|
||||||
// @Success 200
|
// @Success 200 {object} response.NginxRewriteRes
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /websites/rewrite [post]
|
// @Router /websites/rewrite [post]
|
||||||
@@ -552,7 +554,7 @@ func (b *BaseApi) UpdateSiteDirPermission(c *gin.Context) {
|
|||||||
// @Summary Get proxy conf
|
// @Summary Get proxy conf
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body request.WebsiteProxyReq true "request"
|
// @Param request body request.WebsiteProxyReq true "request"
|
||||||
// @Success 200
|
// @Success 200 {array} request.WebsiteProxyConfig
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /websites/proxies [post]
|
// @Router /websites/proxies [post]
|
||||||
@@ -569,6 +571,28 @@ func (b *BaseApi) GetProxyConfig(c *gin.Context) {
|
|||||||
helper.SuccessWithData(c, res)
|
helper.SuccessWithData(c, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @Tags Website
|
||||||
|
// @Summary Delete proxy conf
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body request.WebsiteProxyDel true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Security Timestamp
|
||||||
|
// @Router /websites/proxies/del [post]
|
||||||
|
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"删除网站 [domain] 反向代理配置","formatEN":"Delete domain [domain] proxy config"}
|
||||||
|
func (b *BaseApi) DeleteProxyConfig(c *gin.Context) {
|
||||||
|
var req request.WebsiteProxyDel
|
||||||
|
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err := websiteService.DeleteProxy(req)
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithOutData(c)
|
||||||
|
}
|
||||||
|
|
||||||
// @Tags Website
|
// @Tags Website
|
||||||
// @Summary Update proxy conf
|
// @Summary Update proxy conf
|
||||||
// @Accept json
|
// @Accept json
|
||||||
@@ -616,7 +640,7 @@ func (b *BaseApi) UpdateProxyConfigFile(c *gin.Context) {
|
|||||||
// @Summary Get AuthBasic conf
|
// @Summary Get AuthBasic conf
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body request.NginxAuthReq true "request"
|
// @Param request body request.NginxAuthReq true "request"
|
||||||
// @Success 200
|
// @Success 200 {object} response.NginxAuthRes
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /websites/auths [post]
|
// @Router /websites/auths [post]
|
||||||
@@ -657,7 +681,7 @@ func (b *BaseApi) UpdateAuthConfig(c *gin.Context) {
|
|||||||
// @Summary Get AntiLeech conf
|
// @Summary Get AntiLeech conf
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body request.NginxCommonReq true "request"
|
// @Param request body request.NginxCommonReq true "request"
|
||||||
// @Success 200
|
// @Success 200 {object} response.NginxAntiLeechRes
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /websites/leech [post]
|
// @Router /websites/leech [post]
|
||||||
@@ -720,7 +744,7 @@ func (b *BaseApi) UpdateRedirectConfig(c *gin.Context) {
|
|||||||
// @Summary Get redirect conf
|
// @Summary Get redirect conf
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body request.WebsiteProxyReq true "request"
|
// @Param request body request.WebsiteProxyReq true "request"
|
||||||
// @Success 200
|
// @Success 200 {array} response.NginxRedirectConfig
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /websites/redirect [post]
|
// @Router /websites/redirect [post]
|
||||||
@@ -762,7 +786,7 @@ func (b *BaseApi) UpdateRedirectConfigFile(c *gin.Context) {
|
|||||||
// @Summary Get website dir
|
// @Summary Get website dir
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body request.WebsiteCommonReq true "request"
|
// @Param request body request.WebsiteCommonReq true "request"
|
||||||
// @Success 200
|
// @Success 200 {object} response.WebsiteDirConfig
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /websites/dir [post]
|
// @Router /websites/dir [post]
|
||||||
@@ -782,10 +806,11 @@ func (b *BaseApi) GetDirConfig(c *gin.Context) {
|
|||||||
// @Tags Website
|
// @Tags Website
|
||||||
// @Summary Get default html
|
// @Summary Get default html
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Success 200 {object} response.FileInfo
|
// @Param type path string true "type"
|
||||||
|
// @Success 200 {object} response.WebsiteHtmlRes
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /websites/default/html/:type [get]
|
// @Router /websites/default/html/{type} [get]
|
||||||
func (b *BaseApi) GetDefaultHtml(c *gin.Context) {
|
func (b *BaseApi) GetDefaultHtml(c *gin.Context) {
|
||||||
resourceType, err := helper.GetStrParamByKey(c, "type")
|
resourceType, err := helper.GetStrParamByKey(c, "type")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ func (b *BaseApi) DeleteWebDomain(c *gin.Context) {
|
|||||||
// @Summary Create website domain
|
// @Summary Create website domain
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body request.WebsiteDomainCreate true "request"
|
// @Param request body request.WebsiteDomainCreate true "request"
|
||||||
// @Success 200 {object} model.WebsiteDomain
|
// @Success 200 {array} model.WebsiteDomain
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /websites/domains [post]
|
// @Router /websites/domains [post]
|
||||||
@@ -57,7 +57,7 @@ func (b *BaseApi) CreateWebDomain(c *gin.Context) {
|
|||||||
// @Success 200 {array} model.WebsiteDomain
|
// @Success 200 {array} model.WebsiteDomain
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /websites/domains/:websiteId [get]
|
// @Router /websites/domains/{websiteId} [get]
|
||||||
func (b *BaseApi) GetWebDomains(c *gin.Context) {
|
func (b *BaseApi) GetWebDomains(c *gin.Context) {
|
||||||
websiteId, err := helper.GetIntParamByKey(c, "websiteId")
|
websiteId, err := helper.GetIntParamByKey(c, "websiteId")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import (
|
|||||||
// @Summary Page website ssl
|
// @Summary Page website ssl
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body request.WebsiteSSLSearch true "request"
|
// @Param request body request.WebsiteSSLSearch true "request"
|
||||||
// @Success 200
|
// @Success 200 {array} response.WebsiteSSLDTO
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /websites/ssl/search [post]
|
// @Router /websites/ssl/search [post]
|
||||||
@@ -135,10 +135,10 @@ func (b *BaseApi) DeleteWebsiteSSL(c *gin.Context) {
|
|||||||
// @Summary Search website ssl by website id
|
// @Summary Search website ssl by website id
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param websiteId path integer true "request"
|
// @Param websiteId path integer true "request"
|
||||||
// @Success 200
|
// @Success 200 {object} response.WebsiteSSLDTO
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /websites/ssl/website/:websiteId [get]
|
// @Router /websites/ssl/website/{websiteId} [get]
|
||||||
func (b *BaseApi) GetWebsiteSSLByWebsiteId(c *gin.Context) {
|
func (b *BaseApi) GetWebsiteSSLByWebsiteId(c *gin.Context) {
|
||||||
websiteId, err := helper.GetIntParamByKey(c, "websiteId")
|
websiteId, err := helper.GetIntParamByKey(c, "websiteId")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -157,10 +157,10 @@ func (b *BaseApi) GetWebsiteSSLByWebsiteId(c *gin.Context) {
|
|||||||
// @Summary Search website ssl by id
|
// @Summary Search website ssl by id
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param id path integer true "request"
|
// @Param id path integer true "request"
|
||||||
// @Success 200
|
// @Success 200 {object} response.WebsiteSSLDTO
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /websites/ssl/:id [get]
|
// @Router /websites/ssl/{id} [get]
|
||||||
func (b *BaseApi) GetWebsiteSSLById(c *gin.Context) {
|
func (b *BaseApi) GetWebsiteSSLById(c *gin.Context) {
|
||||||
id, err := helper.GetParamID(c)
|
id, err := helper.GetParamID(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package dto
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
type OllamaModelInfo struct {
|
||||||
|
ID uint `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Size string `json:"size"`
|
||||||
|
From string `json:"from"`
|
||||||
|
LogFileExist bool `json:"logFileExist"`
|
||||||
|
|
||||||
|
Status string `json:"status"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
CreatedAt time.Time `json:"createdAt"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type OllamaModelDropList struct {
|
||||||
|
ID uint `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type OllamaModelName struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type OllamaBindDomain struct {
|
||||||
|
Domain string `json:"domain" validate:"required"`
|
||||||
|
AppInstallID uint `json:"appInstallID" validate:"required"`
|
||||||
|
SSLID uint `json:"sslID"`
|
||||||
|
WebsiteID uint `json:"websiteID"`
|
||||||
|
IPList string `json:"ipList"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type OllamaBindDomainReq struct {
|
||||||
|
AppInstallID uint `json:"appInstallID" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type OllamaBindDomainRes struct {
|
||||||
|
Domain string `json:"domain"`
|
||||||
|
SSLID uint `json:"sslID"`
|
||||||
|
AcmeAccountID uint `json:"acmeAccountID"`
|
||||||
|
AllowIPs []string `json:"allowIPs"`
|
||||||
|
WebsiteID uint `json:"websiteID"`
|
||||||
|
ConnUrl string `json:"connUrl"`
|
||||||
|
}
|
||||||
+21
-10
@@ -1,9 +1,5 @@
|
|||||||
package dto
|
package dto
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
|
||||||
)
|
|
||||||
|
|
||||||
type AppDatabase struct {
|
type AppDatabase struct {
|
||||||
ServiceName string `json:"PANEL_DB_HOST"`
|
ServiceName string `json:"PANEL_DB_HOST"`
|
||||||
DbName string `json:"PANEL_DB_NAME"`
|
DbName string `json:"PANEL_DB_NAME"`
|
||||||
@@ -62,7 +58,7 @@ type AppDefine struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type LocalAppAppDefine struct {
|
type LocalAppAppDefine struct {
|
||||||
AppProperty model.App `json:"additionalProperties" yaml:"additionalProperties"`
|
AppProperty AppProperty `json:"additionalProperties" yaml:"additionalProperties"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type LocalAppParam struct {
|
type LocalAppParam struct {
|
||||||
@@ -82,8 +78,9 @@ type AppProperty struct {
|
|||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Tags []string `json:"tags"`
|
Tags []string `json:"tags"`
|
||||||
ShortDescZh string `json:"shortDescZh"`
|
ShortDescZh string `json:"shortDescZh" yaml:"shortDescZh"`
|
||||||
ShortDescEn string `json:"shortDescEn"`
|
ShortDescEn string `json:"shortDescEn" yaml:"shortDescEn"`
|
||||||
|
Description Locale `json:"description"`
|
||||||
Key string `json:"key"`
|
Key string `json:"key"`
|
||||||
Required []string `json:"Required"`
|
Required []string `json:"Required"`
|
||||||
CrossVersionUpdate bool `json:"crossVersionUpdate"`
|
CrossVersionUpdate bool `json:"crossVersionUpdate"`
|
||||||
@@ -93,6 +90,7 @@ type AppProperty struct {
|
|||||||
Github string `json:"github"`
|
Github string `json:"github"`
|
||||||
Document string `json:"document"`
|
Document string `json:"document"`
|
||||||
Version float64 `json:"version"`
|
Version float64 `json:"version"`
|
||||||
|
GpuSupport bool `json:"gpuSupport"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AppConfigVersion struct {
|
type AppConfigVersion struct {
|
||||||
@@ -104,9 +102,21 @@ type AppConfigVersion struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Tag struct {
|
type Tag struct {
|
||||||
Key string `json:"key"`
|
Key string `json:"key"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Sort int `json:"sort"`
|
Sort int `json:"sort"`
|
||||||
|
Locales Locale `json:"locales"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Locale struct {
|
||||||
|
En string `json:"en"`
|
||||||
|
Ja string `json:"ja"`
|
||||||
|
Ms string `json:"ms"`
|
||||||
|
PtBr string `json:"pt-br" yaml:"pt-br"`
|
||||||
|
Ru string `json:"ru"`
|
||||||
|
ZhHant string `json:"zh-hant" yaml:"zh-hant"`
|
||||||
|
Zh string `json:"zh"`
|
||||||
|
Ko string `json:"ko"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AppForm struct {
|
type AppForm struct {
|
||||||
@@ -118,6 +128,7 @@ type AppFormFields struct {
|
|||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
LabelZh string `json:"labelZh"`
|
LabelZh string `json:"labelZh"`
|
||||||
LabelEn string `json:"labelEn"`
|
LabelEn string `json:"labelEn"`
|
||||||
|
Label Locale `json:"label"`
|
||||||
Required bool `json:"required"`
|
Required bool `json:"required"`
|
||||||
Default interface{} `json:"default"`
|
Default interface{} `json:"default"`
|
||||||
EnvKey string `json:"envKey"`
|
EnvKey string `json:"envKey"`
|
||||||
|
|||||||
+11
-7
@@ -23,13 +23,12 @@ type MfaCredential struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Login struct {
|
type Login struct {
|
||||||
Name string `json:"name" validate:"required"`
|
Name string `json:"name" validate:"required"`
|
||||||
Password string `json:"password" validate:"required"`
|
Password string `json:"password" validate:"required"`
|
||||||
IgnoreCaptcha bool `json:"ignoreCaptcha"`
|
Captcha string `json:"captcha"`
|
||||||
Captcha string `json:"captcha"`
|
CaptchaID string `json:"captchaID"`
|
||||||
CaptchaID string `json:"captchaID"`
|
AuthMethod string `json:"authMethod" validate:"required,oneof=jwt session"`
|
||||||
AuthMethod string `json:"authMethod" validate:"required,oneof=jwt session"`
|
Language string `json:"language" validate:"required,oneof=zh en tw ja ko ru ms 'pt-BR'"`
|
||||||
Language string `json:"language" validate:"required,oneof=zh en tw"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type MFALogin struct {
|
type MFALogin struct {
|
||||||
@@ -38,3 +37,8 @@ type MFALogin struct {
|
|||||||
Code string `json:"code" validate:"required"`
|
Code string `json:"code" validate:"required"`
|
||||||
AuthMethod string `json:"authMethod"`
|
AuthMethod string `json:"authMethod"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type LoginSetting struct {
|
||||||
|
NeedCaptcha bool `json:"needCaptcha"`
|
||||||
|
Language string `json:"language"`
|
||||||
|
}
|
||||||
|
|||||||
@@ -21,6 +21,12 @@ type BackupInfo struct {
|
|||||||
Vars string `json:"vars"`
|
Vars string `json:"vars"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type BackupFile struct {
|
||||||
|
ID uint `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Size int64 `json:"size"`
|
||||||
|
}
|
||||||
|
|
||||||
type OneDriveInfo struct {
|
type OneDriveInfo struct {
|
||||||
ClientID string `json:"client_id"`
|
ClientID string `json:"client_id"`
|
||||||
ClientSecret string `json:"client_secret"`
|
ClientSecret string `json:"client_secret"`
|
||||||
@@ -66,7 +72,6 @@ type BackupRecords struct {
|
|||||||
BackupType string `json:"backupType"`
|
BackupType string `json:"backupType"`
|
||||||
FileDir string `json:"fileDir"`
|
FileDir string `json:"fileDir"`
|
||||||
FileName string `json:"fileName"`
|
FileName string `json:"fileName"`
|
||||||
Size int64 `json:"size"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type DownloadRecord struct {
|
type DownloadRecord struct {
|
||||||
|
|||||||
@@ -52,3 +52,8 @@ type OperationWithNameAndType struct {
|
|||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Type string `json:"type" validate:"required"`
|
Type string `json:"type" validate:"required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ForceDelete struct {
|
||||||
|
IDs []uint `json:"ids"`
|
||||||
|
ForceDelete bool `json:"forceDelete"`
|
||||||
|
}
|
||||||
|
|||||||
@@ -71,14 +71,16 @@ type CronjobDownload struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type CronjobClean struct {
|
type CronjobClean struct {
|
||||||
IsDelete bool `json:"isDelete"`
|
IsDelete bool `json:"isDelete"`
|
||||||
CleanData bool `json:"cleanData"`
|
CleanData bool `json:"cleanData"`
|
||||||
CronjobID uint `json:"cronjobID" validate:"required"`
|
CleanRemoteData bool `json:"cleanRemoteData"`
|
||||||
|
CronjobID uint `json:"cronjobID" validate:"required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type CronjobBatchDelete struct {
|
type CronjobBatchDelete struct {
|
||||||
CleanData bool `json:"cleanData"`
|
CleanData bool `json:"cleanData"`
|
||||||
IDs []uint `json:"ids" validate:"required"`
|
CleanRemoteData bool `json:"cleanRemoteData"`
|
||||||
|
IDs []uint `json:"ids" validate:"required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type CronjobInfo struct {
|
type CronjobInfo struct {
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ type Fail2BanSearch struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Fail2BanUpdate struct {
|
type Fail2BanUpdate struct {
|
||||||
Key string `json:"key" validate:"required,oneof=port bantime findtime maxretry banaction logpath port"`
|
Key string `json:"key" validate:"required,oneof=port bantime findtime maxretry banaction logpath"`
|
||||||
Value string `json:"value"`
|
Value string `json:"value"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,8 @@ type PortRuleOperate struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ForwardRuleOperate struct {
|
type ForwardRuleOperate struct {
|
||||||
Rules []struct {
|
ForceDelete bool `json:"forceDelete"`
|
||||||
|
Rules []struct {
|
||||||
Operation string `json:"operation" validate:"required,oneof=add remove"`
|
Operation string `json:"operation" validate:"required,oneof=add remove"`
|
||||||
Num string `json:"num"`
|
Num string `json:"num"`
|
||||||
Protocol string `json:"protocol" validate:"required,oneof=tcp udp tcp/udp"`
|
Protocol string `json:"protocol" validate:"required,oneof=tcp udp tcp/udp"`
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ type ImageRepoCreate struct {
|
|||||||
Name string `json:"name" validate:"required"`
|
Name string `json:"name" validate:"required"`
|
||||||
DownloadUrl string `json:"downloadUrl"`
|
DownloadUrl string `json:"downloadUrl"`
|
||||||
Protocol string `json:"protocol"`
|
Protocol string `json:"protocol"`
|
||||||
Username string `json:"username" validate:"max=256"`
|
Username string `json:"username"`
|
||||||
Password string `json:"password" validate:"max=256"`
|
Password string `json:"password"`
|
||||||
Auth bool `json:"auth"`
|
Auth bool `json:"auth"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -15,8 +15,8 @@ type ImageRepoUpdate struct {
|
|||||||
ID uint `json:"id"`
|
ID uint `json:"id"`
|
||||||
DownloadUrl string `json:"downloadUrl"`
|
DownloadUrl string `json:"downloadUrl"`
|
||||||
Protocol string `json:"protocol"`
|
Protocol string `json:"protocol"`
|
||||||
Username string `json:"username" validate:"max=256"`
|
Username string `json:"username"`
|
||||||
Password string `json:"password" validate:"max=256"`
|
Password string `json:"password"`
|
||||||
Auth bool `json:"auth"`
|
Auth bool `json:"auth"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package dto
|
||||||
|
|
||||||
|
type DockerComposeService struct {
|
||||||
|
Image string `yaml:"image"`
|
||||||
|
ContainerName string `yaml:"container_name"`
|
||||||
|
Restart string `yaml:"restart"`
|
||||||
|
Ports []string `yaml:"ports"`
|
||||||
|
Environment []string `yaml:"environment"`
|
||||||
|
Command []string `yaml:"command"`
|
||||||
|
}
|
||||||
@@ -33,6 +33,7 @@ type AppContainerConfig struct {
|
|||||||
DockerCompose string `json:"dockerCompose"`
|
DockerCompose string `json:"dockerCompose"`
|
||||||
HostMode bool `json:"hostMode"`
|
HostMode bool `json:"hostMode"`
|
||||||
PullImage bool `json:"pullImage"`
|
PullImage bool `json:"pullImage"`
|
||||||
|
GpuConfig bool `json:"gpuConfig"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AppInstalledSearch struct {
|
type AppInstalledSearch struct {
|
||||||
|
|||||||
@@ -76,7 +76,12 @@ type FileRename struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type FilePathCheck struct {
|
type FilePathCheck struct {
|
||||||
Path string `json:"path" validate:"required"`
|
Path string `json:"path" validate:"required"`
|
||||||
|
WithInit bool `json:"withInit"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type FilePathsCheck struct {
|
||||||
|
Paths []string `json:"paths" validate:"required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type FileWget struct {
|
type FileWget struct {
|
||||||
@@ -87,11 +92,12 @@ type FileWget struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type FileMove struct {
|
type FileMove struct {
|
||||||
Type string `json:"type" validate:"required"`
|
Type string `json:"type" validate:"required"`
|
||||||
OldPaths []string `json:"oldPaths" validate:"required"`
|
OldPaths []string `json:"oldPaths" validate:"required"`
|
||||||
NewPath string `json:"newPath" validate:"required"`
|
NewPath string `json:"newPath" validate:"required"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Cover bool `json:"cover"`
|
Cover bool `json:"cover"`
|
||||||
|
CoverPaths []string `json:"coverPaths"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type FileDownload struct {
|
type FileDownload struct {
|
||||||
|
|||||||
@@ -0,0 +1,57 @@
|
|||||||
|
package request
|
||||||
|
|
||||||
|
import "github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||||
|
|
||||||
|
type McpServerSearch struct {
|
||||||
|
dto.PageInfo
|
||||||
|
Name string `json:"name"`
|
||||||
|
Sync bool `json:"sync"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type McpServerCreate struct {
|
||||||
|
Name string `json:"name" validate:"required"`
|
||||||
|
Command string `json:"command" validate:"required"`
|
||||||
|
Environments []Environment `json:"environments"`
|
||||||
|
Volumes []Volume `json:"volumes"`
|
||||||
|
Port int `json:"port" validate:"required"`
|
||||||
|
ContainerName string `json:"containerName"`
|
||||||
|
BaseURL string `json:"baseUrl"`
|
||||||
|
SsePath string `json:"ssePath"`
|
||||||
|
HostIP string `json:"hostIP"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type McpServerUpdate struct {
|
||||||
|
ID uint `json:"id" validate:"required"`
|
||||||
|
McpServerCreate
|
||||||
|
}
|
||||||
|
|
||||||
|
type Environment struct {
|
||||||
|
Key string `json:"key"`
|
||||||
|
Value string `json:"value"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Volume struct {
|
||||||
|
Source string `json:"source"`
|
||||||
|
Target string `json:"target"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type McpServerDelete struct {
|
||||||
|
ID uint `json:"id" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type McpServerOperate struct {
|
||||||
|
ID uint `json:"id" validate:"required"`
|
||||||
|
Operate string `json:"operate" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type McpBindDomain struct {
|
||||||
|
Domain string `json:"domain" validate:"required"`
|
||||||
|
SSLID uint `json:"sslID"`
|
||||||
|
IPList string `json:"ipList"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type McpBindDomainUpdate struct {
|
||||||
|
WebsiteID uint `json:"websiteID" validate:"required"`
|
||||||
|
SSLID uint `json:"sslID"`
|
||||||
|
IPList string `json:"ipList"`
|
||||||
|
}
|
||||||
@@ -193,6 +193,11 @@ type WebsiteProxyConfig struct {
|
|||||||
ProxySSLName string `json:"proxySSLName"`
|
ProxySSLName string `json:"proxySSLName"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type WebsiteProxyDel struct {
|
||||||
|
ID uint `json:"id" validate:"required"`
|
||||||
|
Name string `json:"name" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
type WebsiteProxyReq struct {
|
type WebsiteProxyReq struct {
|
||||||
ID uint `json:"id" validate:"required"`
|
ID uint `json:"id" validate:"required"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type AppRes struct {
|
type AppRes struct {
|
||||||
Items []*AppDto `json:"items"`
|
Items []*AppItem `json:"items"`
|
||||||
Total int64 `json:"total"`
|
Total int64 `json:"total"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AppUpdateRes struct {
|
type AppUpdateRes struct {
|
||||||
@@ -23,29 +23,31 @@ type AppUpdateRes struct {
|
|||||||
|
|
||||||
type AppDTO struct {
|
type AppDTO struct {
|
||||||
model.App
|
model.App
|
||||||
Installed bool `json:"installed"`
|
Installed bool `json:"installed"`
|
||||||
Versions []string `json:"versions"`
|
Versions []string `json:"versions"`
|
||||||
Tags []model.Tag `json:"tags"`
|
Tags []TagDTO `json:"tags"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AppDto struct {
|
type AppItem struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Key string `json:"key"`
|
Key string `json:"key"`
|
||||||
ID uint `json:"id"`
|
ID uint `json:"id"`
|
||||||
ShortDescZh string `json:"shortDescZh"`
|
Description string `json:"description"`
|
||||||
ShortDescEn string `json:"shortDescEn"`
|
Icon string `json:"icon"`
|
||||||
Icon string `json:"icon"`
|
Type string `json:"type"`
|
||||||
Type string `json:"type"`
|
Status string `json:"status"`
|
||||||
Status string `json:"status"`
|
Resource string `json:"resource"`
|
||||||
Resource string `json:"resource"`
|
Installed bool `json:"installed"`
|
||||||
Installed bool `json:"installed"`
|
Versions []string `json:"versions"`
|
||||||
Versions []string `json:"versions"`
|
Limit int `json:"limit"`
|
||||||
Limit int `json:"limit"`
|
Tags []TagDTO `json:"tags"`
|
||||||
Tags []model.Tag `json:"tags"`
|
GpuSupport bool `json:"gpuSupport"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type TagDTO struct {
|
type TagDTO struct {
|
||||||
model.Tag
|
ID uint `json:"id"`
|
||||||
|
Key string `json:"key"`
|
||||||
|
Name string `json:"name"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AppInstalledCheck struct {
|
type AppInstalledCheck struct {
|
||||||
@@ -65,10 +67,11 @@ type AppInstalledCheck struct {
|
|||||||
|
|
||||||
type AppDetailDTO struct {
|
type AppDetailDTO struct {
|
||||||
model.AppDetail
|
model.AppDetail
|
||||||
Enable bool `json:"enable"`
|
Enable bool `json:"enable"`
|
||||||
Params interface{} `json:"params"`
|
Params interface{} `json:"params"`
|
||||||
Image string `json:"image"`
|
Image string `json:"image"`
|
||||||
HostMode bool `json:"hostMode"`
|
HostMode bool `json:"hostMode"`
|
||||||
|
GpuSupport bool `json:"gpuSupport"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type IgnoredApp struct {
|
type IgnoredApp struct {
|
||||||
@@ -89,9 +92,10 @@ type AppInstalledDTO struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type AppDetail struct {
|
type AppDetail struct {
|
||||||
Website string `json:"website"`
|
Website string `json:"website"`
|
||||||
Document string `json:"document"`
|
Document string `json:"document"`
|
||||||
Github string `json:"github"`
|
Github string `json:"github"`
|
||||||
|
GpuSupport bool `json:"gpuSupport"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AppInstallDTO struct {
|
type AppInstallDTO struct {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package response
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type FileInfo struct {
|
type FileInfo struct {
|
||||||
@@ -46,3 +47,11 @@ type FileLineContent struct {
|
|||||||
type FileExist struct {
|
type FileExist struct {
|
||||||
Exist bool `json:"exist"`
|
Exist bool `json:"exist"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ExistFileInfo struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Path string `json:"path"`
|
||||||
|
Size float64 `json:"size"`
|
||||||
|
ModTime time.Time `json:"modTime"`
|
||||||
|
IsDir bool `json:"isDir"`
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package response
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
type McpServersRes struct {
|
||||||
|
Items []McpServerDTO `json:"items"`
|
||||||
|
Total int64 `json:"total"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type McpServerDTO struct {
|
||||||
|
model.McpServer
|
||||||
|
Environments []request.Environment `json:"environments"`
|
||||||
|
Volumes []request.Volume `json:"volumes"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type McpBindDomainRes struct {
|
||||||
|
Domain string `json:"domain"`
|
||||||
|
SSLID uint `json:"sslID"`
|
||||||
|
AcmeAccountID uint `json:"acmeAccountID"`
|
||||||
|
AllowIPs []string `json:"allowIPs"`
|
||||||
|
WebsiteID uint `json:"websiteID"`
|
||||||
|
ConnUrl string `json:"connUrl"`
|
||||||
|
}
|
||||||
@@ -70,6 +70,8 @@ type SettingInfo struct {
|
|||||||
ApiInterfaceStatus string `json:"apiInterfaceStatus"`
|
ApiInterfaceStatus string `json:"apiInterfaceStatus"`
|
||||||
ApiKey string `json:"apiKey"`
|
ApiKey string `json:"apiKey"`
|
||||||
IpWhiteList string `json:"ipWhiteList"`
|
IpWhiteList string `json:"ipWhiteList"`
|
||||||
|
ApiKeyValidityTime string `json:"apiKeyValidityTime"`
|
||||||
|
LicenseVerify string `json:"licenseVerify"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type SettingUpdate struct {
|
type SettingUpdate struct {
|
||||||
@@ -240,4 +242,5 @@ type ApiInterfaceConfig struct {
|
|||||||
ApiInterfaceStatus string `json:"apiInterfaceStatus"`
|
ApiInterfaceStatus string `json:"apiInterfaceStatus"`
|
||||||
ApiKey string `json:"apiKey"`
|
ApiKey string `json:"apiKey"`
|
||||||
IpWhiteList string `json:"ipWhiteList"`
|
IpWhiteList string `json:"ipWhiteList"`
|
||||||
|
ApiKeyValidityTime string `json:"apiKeyValidityTime"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
type OllamaModel struct {
|
||||||
|
BaseModel
|
||||||
|
|
||||||
|
Name string `json:"name"`
|
||||||
|
Size string `json:"size"`
|
||||||
|
From string `json:"from"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
}
|
||||||
@@ -1,7 +1,10 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
@@ -12,10 +15,12 @@ type App struct {
|
|||||||
Key string `json:"key" gorm:"type:varchar(64);not null;"`
|
Key string `json:"key" gorm:"type:varchar(64);not null;"`
|
||||||
ShortDescZh string `json:"shortDescZh" yaml:"shortDescZh" gorm:"type:longtext;"`
|
ShortDescZh string `json:"shortDescZh" yaml:"shortDescZh" gorm:"type:longtext;"`
|
||||||
ShortDescEn string `json:"shortDescEn" yaml:"shortDescEn" gorm:"type:longtext;"`
|
ShortDescEn string `json:"shortDescEn" yaml:"shortDescEn" gorm:"type:longtext;"`
|
||||||
|
Description string `json:"description"`
|
||||||
Icon string `json:"icon" gorm:"type:longtext;"`
|
Icon string `json:"icon" gorm:"type:longtext;"`
|
||||||
Type string `json:"type" gorm:"type:varchar(64);not null"`
|
Type string `json:"type" gorm:"type:varchar(64);not null"`
|
||||||
Status string `json:"status" gorm:"type:varchar(64);not null"`
|
Status string `json:"status" gorm:"type:varchar(64);not null"`
|
||||||
Required string `json:"required" gorm:"type:varchar(64);"`
|
Required string `json:"required" gorm:"type:varchar(64);"`
|
||||||
|
GpuSupport bool `json:"gpuSupport"`
|
||||||
CrossVersionUpdate bool `json:"crossVersionUpdate" yaml:"crossVersionUpdate"`
|
CrossVersionUpdate bool `json:"crossVersionUpdate" yaml:"crossVersionUpdate"`
|
||||||
Limit int `json:"limit" gorm:"type:Integer;not null"`
|
Limit int `json:"limit" gorm:"type:Integer;not null"`
|
||||||
Website string `json:"website" gorm:"type:varchar(64);not null"`
|
Website string `json:"website" gorm:"type:varchar(64);not null"`
|
||||||
@@ -36,8 +41,20 @@ func (i *App) IsLocalApp() bool {
|
|||||||
}
|
}
|
||||||
func (i *App) GetAppResourcePath() string {
|
func (i *App) GetAppResourcePath() string {
|
||||||
if i.IsLocalApp() {
|
if i.IsLocalApp() {
|
||||||
//这里要去掉本地应用的local前缀
|
|
||||||
return filepath.Join(constant.LocalAppResourceDir, strings.TrimPrefix(i.Key, "local"))
|
return filepath.Join(constant.LocalAppResourceDir, strings.TrimPrefix(i.Key, "local"))
|
||||||
}
|
}
|
||||||
return filepath.Join(constant.RemoteAppResourceDir, i.Key)
|
return filepath.Join(constant.RemoteAppResourceDir, i.Key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (i *App) GetDescription(ctx *gin.Context) string {
|
||||||
|
var translations = make(map[string]string)
|
||||||
|
_ = json.Unmarshal([]byte(i.Description), &translations)
|
||||||
|
lang := strings.ToLower(common.GetLang(ctx))
|
||||||
|
if desc, ok := translations[lang]; ok && desc != "" {
|
||||||
|
return desc
|
||||||
|
}
|
||||||
|
if lang == "zh" {
|
||||||
|
return i.ShortDescZh
|
||||||
|
}
|
||||||
|
return i.ShortDescEn
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
type McpServer struct {
|
||||||
|
BaseModel
|
||||||
|
Name string `json:"name"`
|
||||||
|
DockerCompose string `json:"dockerCompose"`
|
||||||
|
Command string `json:"command"`
|
||||||
|
ContainerName string `json:"containerName"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
Port int `json:"port"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
Env string `json:"env"`
|
||||||
|
BaseURL string `json:"baseUrl"`
|
||||||
|
SsePath string `json:"ssePath"`
|
||||||
|
WebsiteID int `json:"websiteID"`
|
||||||
|
Dir string `json:"dir"`
|
||||||
|
HostIP string `json:"hostIP"`
|
||||||
|
}
|
||||||
@@ -2,7 +2,8 @@ package model
|
|||||||
|
|
||||||
type Tag struct {
|
type Tag struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Key string `json:"key" gorm:"type:varchar(64);not null"`
|
Key string `json:"key" gorm:"type:varchar(64);not null"`
|
||||||
Name string `json:"name" gorm:"type:varchar(64);not null"`
|
Name string `json:"name" gorm:"type:varchar(64);not null"`
|
||||||
Sort int `json:"sort" gorm:"type:int;not null;default:1"`
|
Translations string `json:"translations"`
|
||||||
|
Sort int `json:"sort" gorm:"type:int;not null;default:1"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,69 @@
|
|||||||
|
package repo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/global"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AiRepo struct{}
|
||||||
|
|
||||||
|
type IAiRepo interface {
|
||||||
|
Get(opts ...DBOption) (model.OllamaModel, error)
|
||||||
|
List(opts ...DBOption) ([]model.OllamaModel, error)
|
||||||
|
Page(limit, offset int, opts ...DBOption) (int64, []model.OllamaModel, error)
|
||||||
|
Create(cronjob *model.OllamaModel) error
|
||||||
|
Update(id uint, vars map[string]interface{}) error
|
||||||
|
Delete(opts ...DBOption) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewIAiRepo() IAiRepo {
|
||||||
|
return &AiRepo{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *AiRepo) Get(opts ...DBOption) (model.OllamaModel, error) {
|
||||||
|
var item model.OllamaModel
|
||||||
|
db := global.DB
|
||||||
|
for _, opt := range opts {
|
||||||
|
db = opt(db)
|
||||||
|
}
|
||||||
|
err := db.First(&item).Error
|
||||||
|
return item, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *AiRepo) List(opts ...DBOption) ([]model.OllamaModel, error) {
|
||||||
|
var list []model.OllamaModel
|
||||||
|
db := global.DB.Model(&model.OllamaModel{})
|
||||||
|
for _, opt := range opts {
|
||||||
|
db = opt(db)
|
||||||
|
}
|
||||||
|
err := db.Find(&list).Error
|
||||||
|
return list, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *AiRepo) Page(page, size int, opts ...DBOption) (int64, []model.OllamaModel, error) {
|
||||||
|
var list []model.OllamaModel
|
||||||
|
db := global.DB.Model(&model.OllamaModel{})
|
||||||
|
for _, opt := range opts {
|
||||||
|
db = opt(db)
|
||||||
|
}
|
||||||
|
count := int64(0)
|
||||||
|
db = db.Count(&count)
|
||||||
|
err := db.Limit(size).Offset(size * (page - 1)).Find(&list).Error
|
||||||
|
return count, list, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *AiRepo) Create(item *model.OllamaModel) error {
|
||||||
|
return global.DB.Create(item).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *AiRepo) Update(id uint, vars map[string]interface{}) error {
|
||||||
|
return global.DB.Model(&model.OllamaModel{}).Where("id = ?", id).Updates(vars).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *AiRepo) Delete(opts ...DBOption) error {
|
||||||
|
db := global.DB
|
||||||
|
for _, opt := range opts {
|
||||||
|
db = opt(db)
|
||||||
|
}
|
||||||
|
return db.Delete(&model.OllamaModel{}).Error
|
||||||
|
}
|
||||||
@@ -15,6 +15,7 @@ type DBOption func(*gorm.DB) *gorm.DB
|
|||||||
type ICommonRepo interface {
|
type ICommonRepo interface {
|
||||||
WithByID(id uint) DBOption
|
WithByID(id uint) DBOption
|
||||||
WithByName(name string) DBOption
|
WithByName(name string) DBOption
|
||||||
|
WithByLowerName(name string) DBOption
|
||||||
WithByType(tp string) DBOption
|
WithByType(tp string) DBOption
|
||||||
WithOrderBy(orderStr string) DBOption
|
WithOrderBy(orderStr string) DBOption
|
||||||
WithOrderRuleBy(orderBy, order string) DBOption
|
WithOrderRuleBy(orderBy, order string) DBOption
|
||||||
@@ -45,6 +46,12 @@ func (c *CommonRepo) WithByName(name string) DBOption {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *CommonRepo) WithByLowerName(name string) DBOption {
|
||||||
|
return func(g *gorm.DB) *gorm.DB {
|
||||||
|
return g.Where("LOWER(name) = LOWER(?)", name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (c *CommonRepo) WithByDate(startTime, endTime time.Time) DBOption {
|
func (c *CommonRepo) WithByDate(startTime, endTime time.Time) DBOption {
|
||||||
return func(g *gorm.DB) *gorm.DB {
|
return func(g *gorm.DB) *gorm.DB {
|
||||||
return g.Where("start_time > ? AND start_time < ?", startTime, endTime)
|
return g.Where("start_time > ? AND start_time < ?", startTime, endTime)
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ type IGroupRepo interface {
|
|||||||
Delete(opts ...DBOption) error
|
Delete(opts ...DBOption) error
|
||||||
CancelDefault(groupType string) error
|
CancelDefault(groupType string) error
|
||||||
WithByHostDefault() DBOption
|
WithByHostDefault() DBOption
|
||||||
|
WithByWebsiteDefault() DBOption
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewIGroupRepo() IGroupRepo {
|
func NewIGroupRepo() IGroupRepo {
|
||||||
@@ -56,6 +57,12 @@ func (u *GroupRepo) WithByHostDefault() DBOption {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *GroupRepo) WithByWebsiteDefault() DBOption {
|
||||||
|
return func(g *gorm.DB) *gorm.DB {
|
||||||
|
return g.Where("is_default = ? AND type = ?", 1, "website")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (u *GroupRepo) Delete(opts ...DBOption) error {
|
func (u *GroupRepo) Delete(opts ...DBOption) error {
|
||||||
db := global.DB
|
db := global.DB
|
||||||
for _, opt := range opts {
|
for _, opt := range opts {
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package repo
|
||||||
|
|
||||||
|
import "github.com/1Panel-dev/1Panel/backend/app/model"
|
||||||
|
|
||||||
|
type McpServerRepo struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
type IMcpServerRepo interface {
|
||||||
|
Page(page, size int, opts ...DBOption) (int64, []model.McpServer, error)
|
||||||
|
GetFirst(opts ...DBOption) (*model.McpServer, error)
|
||||||
|
Create(mcpServer *model.McpServer) error
|
||||||
|
Save(mcpServer *model.McpServer) error
|
||||||
|
DeleteBy(opts ...DBOption) error
|
||||||
|
List(opts ...DBOption) ([]model.McpServer, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewIMcpServerRepo() IMcpServerRepo {
|
||||||
|
return &McpServerRepo{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m McpServerRepo) Page(page, size int, opts ...DBOption) (int64, []model.McpServer, error) {
|
||||||
|
var servers []model.McpServer
|
||||||
|
db := getDb(opts...).Model(&model.McpServer{})
|
||||||
|
count := int64(0)
|
||||||
|
db = db.Count(&count)
|
||||||
|
err := db.Limit(size).Offset(size * (page - 1)).Find(&servers).Error
|
||||||
|
return count, servers, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m McpServerRepo) GetFirst(opts ...DBOption) (*model.McpServer, error) {
|
||||||
|
var mcpServer model.McpServer
|
||||||
|
if err := getDb(opts...).First(&mcpServer).Error; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &mcpServer, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m McpServerRepo) List(opts ...DBOption) ([]model.McpServer, error) {
|
||||||
|
var mcpServers []model.McpServer
|
||||||
|
if err := getDb(opts...).Find(&mcpServers).Error; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return mcpServers, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m McpServerRepo) Create(mcpServer *model.McpServer) error {
|
||||||
|
return getDb().Create(mcpServer).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m McpServerRepo) Save(mcpServer *model.McpServer) error {
|
||||||
|
return getDb().Save(mcpServer).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m McpServerRepo) DeleteBy(opts ...DBOption) error {
|
||||||
|
return getDb(opts...).Delete(&model.McpServer{}).Error
|
||||||
|
}
|
||||||
@@ -16,6 +16,7 @@ type ISettingRepo interface {
|
|||||||
Create(key, value string) error
|
Create(key, value string) error
|
||||||
Update(key, value string) error
|
Update(key, value string) error
|
||||||
WithByKey(key string) DBOption
|
WithByKey(key string) DBOption
|
||||||
|
UpdateOrCreate(key, value string) error
|
||||||
|
|
||||||
CreateMonitorBase(model model.MonitorBase) error
|
CreateMonitorBase(model model.MonitorBase) error
|
||||||
BatchCreateMonitorIO(ioList []model.MonitorIO) error
|
BatchCreateMonitorIO(ioList []model.MonitorIO) error
|
||||||
@@ -85,3 +86,7 @@ func (u *SettingRepo) DelMonitorIO(timeForDelete time.Time) error {
|
|||||||
func (u *SettingRepo) DelMonitorNet(timeForDelete time.Time) error {
|
func (u *SettingRepo) DelMonitorNet(timeForDelete time.Time) error {
|
||||||
return global.MonitorDB.Where("created_at < ?", timeForDelete).Delete(&model.MonitorNetwork{}).Error
|
return global.MonitorDB.Where("created_at < ?", timeForDelete).Delete(&model.MonitorNetwork{}).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *SettingRepo) UpdateOrCreate(key, value string) error {
|
||||||
|
return global.DB.Model(&model.Setting{}).Where("key = ?", key).Assign(model.Setting{Key: key, Value: value}).FirstOrCreate(&model.Setting{}).Error
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,415 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
||||||
|
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/app/repo"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/global"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
||||||
|
"github.com/jinzhu/copier"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AIToolService struct{}
|
||||||
|
|
||||||
|
type IAIToolService interface {
|
||||||
|
Search(search dto.SearchWithPage) (int64, []dto.OllamaModelInfo, error)
|
||||||
|
Create(name string) error
|
||||||
|
Close(name string) error
|
||||||
|
Recreate(name string) error
|
||||||
|
Delete(req dto.ForceDelete) error
|
||||||
|
Sync() ([]dto.OllamaModelDropList, error)
|
||||||
|
LoadDetail(name string) (string, error)
|
||||||
|
BindDomain(req dto.OllamaBindDomain) error
|
||||||
|
GetBindDomain(req dto.OllamaBindDomainReq) (*dto.OllamaBindDomainRes, error)
|
||||||
|
UpdateBindDomain(req dto.OllamaBindDomain) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewIAIToolService() IAIToolService {
|
||||||
|
return &AIToolService{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *AIToolService) Search(req dto.SearchWithPage) (int64, []dto.OllamaModelInfo, error) {
|
||||||
|
var options []repo.DBOption
|
||||||
|
if len(req.Info) != 0 {
|
||||||
|
options = append(options, commonRepo.WithLikeName(req.Info))
|
||||||
|
}
|
||||||
|
total, list, err := aiRepo.Page(req.Page, req.PageSize, options...)
|
||||||
|
if err != nil {
|
||||||
|
return 0, nil, err
|
||||||
|
}
|
||||||
|
var dtoLists []dto.OllamaModelInfo
|
||||||
|
for _, itemModel := range list {
|
||||||
|
var item dto.OllamaModelInfo
|
||||||
|
if err := copier.Copy(&item, &itemModel); err != nil {
|
||||||
|
return 0, nil, errors.WithMessage(constant.ErrStructTransform, err.Error())
|
||||||
|
}
|
||||||
|
logPath := path.Join(global.CONF.System.DataDir, "log", "AITools", itemModel.Name)
|
||||||
|
if _, err := os.Stat(logPath); err == nil {
|
||||||
|
item.LogFileExist = true
|
||||||
|
}
|
||||||
|
dtoLists = append(dtoLists, item)
|
||||||
|
}
|
||||||
|
return int64(total), dtoLists, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *AIToolService) LoadDetail(name string) (string, error) {
|
||||||
|
if cmd.CheckIllegal(name) {
|
||||||
|
return "", buserr.New(constant.ErrCmdIllegal)
|
||||||
|
}
|
||||||
|
containerName, err := LoadContainerName()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
stdout, err := cmd.Execf("docker exec %s ollama show %s", containerName, name)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return stdout, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *AIToolService) Create(name string) error {
|
||||||
|
if cmd.CheckIllegal(name) {
|
||||||
|
return buserr.New(constant.ErrCmdIllegal)
|
||||||
|
}
|
||||||
|
modelInfo, _ := aiRepo.Get(commonRepo.WithByName(name))
|
||||||
|
if modelInfo.ID != 0 {
|
||||||
|
return constant.ErrRecordExist
|
||||||
|
}
|
||||||
|
containerName, err := LoadContainerName()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logItem := path.Join(global.CONF.System.DataDir, "log", "AITools", name)
|
||||||
|
if _, err := os.Stat(path.Dir(logItem)); err != nil && os.IsNotExist(err) {
|
||||||
|
if err = os.MkdirAll(path.Dir(logItem), os.ModePerm); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
info := model.OllamaModel{
|
||||||
|
Name: name,
|
||||||
|
From: "local",
|
||||||
|
Status: constant.StatusWaiting,
|
||||||
|
}
|
||||||
|
if err := aiRepo.Create(&info); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
file, err := os.OpenFile(logItem, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
go pullOllamaModel(file, containerName, info)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *AIToolService) Close(name string) error {
|
||||||
|
if cmd.CheckIllegal(name) {
|
||||||
|
return buserr.New(constant.ErrCmdIllegal)
|
||||||
|
}
|
||||||
|
containerName, err := LoadContainerName()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
stdout, err := cmd.Execf("docker exec %s ollama stop %s", containerName, name)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("handle ollama stop %s failed, stdout: %s, err: %v", name, stdout, err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *AIToolService) Recreate(name string) error {
|
||||||
|
if cmd.CheckIllegal(name) {
|
||||||
|
return buserr.New(constant.ErrCmdIllegal)
|
||||||
|
}
|
||||||
|
modelInfo, _ := aiRepo.Get(commonRepo.WithByName(name))
|
||||||
|
if modelInfo.ID == 0 {
|
||||||
|
return constant.ErrRecordNotFound
|
||||||
|
}
|
||||||
|
containerName, err := LoadContainerName()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := aiRepo.Update(modelInfo.ID, map[string]interface{}{"status": constant.StatusWaiting, "from": "local"}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logItem := path.Join(global.CONF.System.DataDir, "log", "AITools", name)
|
||||||
|
if _, err := os.Stat(path.Dir(logItem)); err != nil && os.IsNotExist(err) {
|
||||||
|
if err = os.MkdirAll(path.Dir(logItem), os.ModePerm); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file, err := os.OpenFile(logItem, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
go pullOllamaModel(file, containerName, modelInfo)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *AIToolService) Delete(req dto.ForceDelete) error {
|
||||||
|
ollamaList, _ := aiRepo.List(commonRepo.WithIdsIn(req.IDs))
|
||||||
|
if len(ollamaList) == 0 {
|
||||||
|
return constant.ErrRecordNotFound
|
||||||
|
}
|
||||||
|
containerName, err := LoadContainerName()
|
||||||
|
if err != nil && !req.ForceDelete {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, item := range ollamaList {
|
||||||
|
if item.Status != constant.StatusDeleted {
|
||||||
|
stdout, err := cmd.Execf("docker exec %s ollama rm %s", containerName, item.Name)
|
||||||
|
if err != nil && !req.ForceDelete {
|
||||||
|
return fmt.Errorf("handle ollama rm %s failed, stdout: %s, err: %v", item.Name, stdout, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ = aiRepo.Delete(commonRepo.WithByID(item.ID))
|
||||||
|
logItem := path.Join(global.CONF.System.DataDir, "log", "AITools", item.Name)
|
||||||
|
_ = os.Remove(logItem)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *AIToolService) Sync() ([]dto.OllamaModelDropList, error) {
|
||||||
|
containerName, err := LoadContainerName()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
stdout, err := cmd.Execf("docker exec %s ollama list", containerName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var list []model.OllamaModel
|
||||||
|
lines := strings.Split(stdout, "\n")
|
||||||
|
for _, line := range lines {
|
||||||
|
parts := strings.Fields(line)
|
||||||
|
if len(parts) < 5 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if parts[0] == "NAME" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
list = append(list, model.OllamaModel{Name: parts[0], Size: parts[2] + " " + parts[3]})
|
||||||
|
}
|
||||||
|
listInDB, _ := aiRepo.List()
|
||||||
|
var dropList []dto.OllamaModelDropList
|
||||||
|
for _, itemModel := range listInDB {
|
||||||
|
isExit := false
|
||||||
|
for i := 0; i < len(list); i++ {
|
||||||
|
if list[i].Name == itemModel.Name {
|
||||||
|
_ = aiRepo.Update(itemModel.ID, map[string]interface{}{"status": constant.StatusSuccess, "message": "", "size": list[i].Size})
|
||||||
|
list = append(list[:i], list[(i+1):]...)
|
||||||
|
isExit = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !isExit && itemModel.Status != constant.StatusWaiting {
|
||||||
|
_ = aiRepo.Update(itemModel.ID, map[string]interface{}{"status": constant.StatusDeleted, "message": "not exist", "size": ""})
|
||||||
|
dropList = append(dropList, dto.OllamaModelDropList{ID: itemModel.ID, Name: itemModel.Name})
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, item := range list {
|
||||||
|
item.Status = constant.StatusSuccess
|
||||||
|
item.From = "remote"
|
||||||
|
_ = aiRepo.Create(&item)
|
||||||
|
}
|
||||||
|
|
||||||
|
return dropList, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *AIToolService) BindDomain(req dto.OllamaBindDomain) error {
|
||||||
|
nginxInstall, _ := getAppInstallByKey(constant.AppOpenresty)
|
||||||
|
if nginxInstall.ID == 0 {
|
||||||
|
return buserr.New("ErrOpenrestyInstall")
|
||||||
|
}
|
||||||
|
var (
|
||||||
|
ipList []string
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
if len(req.IPList) > 0 {
|
||||||
|
ipList, err = common.HandleIPList(req.IPList)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if req.SSLID > 0 {
|
||||||
|
ssl, err := websiteSSLRepo.GetFirst(commonRepo.WithByID(req.SSLID))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if ssl.Pem == "" {
|
||||||
|
return buserr.New("ErrSSL")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
createWebsiteReq := request.WebsiteCreate{
|
||||||
|
PrimaryDomain: req.Domain,
|
||||||
|
Alias: strings.ToLower(req.Domain),
|
||||||
|
Type: constant.Deployment,
|
||||||
|
AppType: constant.InstalledApp,
|
||||||
|
AppInstallID: req.AppInstallID,
|
||||||
|
}
|
||||||
|
websiteService := NewIWebsiteService()
|
||||||
|
if err := websiteService.CreateWebsite(createWebsiteReq); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
website, err := websiteRepo.GetFirst(websiteRepo.WithAlias(strings.ToLower(req.Domain)))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(ipList) > 0 {
|
||||||
|
if err = ConfigAllowIPs(ipList, website); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if req.SSLID > 0 {
|
||||||
|
sslReq := request.WebsiteHTTPSOp{
|
||||||
|
WebsiteID: website.ID,
|
||||||
|
Enable: true,
|
||||||
|
Type: "existed",
|
||||||
|
WebsiteSSLID: req.SSLID,
|
||||||
|
HttpConfig: "HTTPSOnly",
|
||||||
|
}
|
||||||
|
if _, err = websiteService.OpWebsiteHTTPS(context.Background(), sslReq); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err = ConfigAIProxy(website); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *AIToolService) GetBindDomain(req dto.OllamaBindDomainReq) (*dto.OllamaBindDomainRes, error) {
|
||||||
|
install, err := appInstallRepo.GetFirst(commonRepo.WithByID(req.AppInstallID))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
res := &dto.OllamaBindDomainRes{}
|
||||||
|
website, _ := websiteRepo.GetFirst(websiteRepo.WithAppInstallId(install.ID))
|
||||||
|
if website.ID == 0 {
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
res.WebsiteID = website.ID
|
||||||
|
res.Domain = website.PrimaryDomain
|
||||||
|
if website.WebsiteSSLID > 0 {
|
||||||
|
res.SSLID = website.WebsiteSSLID
|
||||||
|
ssl, _ := websiteSSLRepo.GetFirst(commonRepo.WithByID(website.WebsiteSSLID))
|
||||||
|
res.AcmeAccountID = ssl.AcmeAccountID
|
||||||
|
}
|
||||||
|
res.ConnUrl = fmt.Sprintf("%s://%s", strings.ToLower(website.Protocol), website.PrimaryDomain)
|
||||||
|
res.AllowIPs = GetAllowIps(website)
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *AIToolService) UpdateBindDomain(req dto.OllamaBindDomain) error {
|
||||||
|
nginxInstall, _ := getAppInstallByKey(constant.AppOpenresty)
|
||||||
|
if nginxInstall.ID == 0 {
|
||||||
|
return buserr.New("ErrOpenrestyInstall")
|
||||||
|
}
|
||||||
|
var (
|
||||||
|
ipList []string
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
if len(req.IPList) > 0 {
|
||||||
|
ipList, err = common.HandleIPList(req.IPList)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if req.SSLID > 0 {
|
||||||
|
ssl, err := websiteSSLRepo.GetFirst(commonRepo.WithByID(req.SSLID))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if ssl.Pem == "" {
|
||||||
|
return buserr.New("ErrSSL")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
websiteService := NewIWebsiteService()
|
||||||
|
website, err := websiteRepo.GetFirst(commonRepo.WithByID(req.WebsiteID))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err = ConfigAllowIPs(ipList, website); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if req.SSLID > 0 {
|
||||||
|
sslReq := request.WebsiteHTTPSOp{
|
||||||
|
WebsiteID: website.ID,
|
||||||
|
Enable: true,
|
||||||
|
Type: "existed",
|
||||||
|
WebsiteSSLID: req.SSLID,
|
||||||
|
HttpConfig: "HTTPSOnly",
|
||||||
|
}
|
||||||
|
if _, err = websiteService.OpWebsiteHTTPS(context.Background(), sslReq); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if website.WebsiteSSLID > 0 && req.SSLID == 0 {
|
||||||
|
sslReq := request.WebsiteHTTPSOp{
|
||||||
|
WebsiteID: website.ID,
|
||||||
|
Enable: false,
|
||||||
|
}
|
||||||
|
if _, err = websiteService.OpWebsiteHTTPS(context.Background(), sslReq); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func LoadContainerName() (string, error) {
|
||||||
|
ollamaBaseInfo, err := appInstallRepo.LoadBaseInfo("ollama", "")
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("ollama service is not found, err: %v", err)
|
||||||
|
}
|
||||||
|
if ollamaBaseInfo.Status != constant.Running {
|
||||||
|
return "", fmt.Errorf("container %s of ollama is not running, please check and retry!", ollamaBaseInfo.ContainerName)
|
||||||
|
}
|
||||||
|
return ollamaBaseInfo.ContainerName, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func pullOllamaModel(file *os.File, containerName string, info model.OllamaModel) {
|
||||||
|
defer file.Close()
|
||||||
|
cmd := exec.Command("docker", "exec", containerName, "ollama", "pull", info.Name)
|
||||||
|
multiWriter := io.MultiWriter(os.Stdout, file)
|
||||||
|
cmd.Stdout = multiWriter
|
||||||
|
cmd.Stderr = multiWriter
|
||||||
|
_ = cmd.Run()
|
||||||
|
itemSize, err := loadModelSize(info.Name, containerName)
|
||||||
|
if len(itemSize) != 0 {
|
||||||
|
_ = aiRepo.Update(info.ID, map[string]interface{}{"status": constant.StatusSuccess, "size": itemSize})
|
||||||
|
} else {
|
||||||
|
_ = aiRepo.Update(info.ID, map[string]interface{}{"status": constant.StatusFailed, "message": err.Error()})
|
||||||
|
}
|
||||||
|
_, _ = file.WriteString("ollama pull completed!")
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadModelSize(name string, containerName string) (string, error) {
|
||||||
|
stdout, err := cmd.Execf("docker exec %s ollama list | grep %s", containerName, name)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
lines := strings.Split(string(stdout), "\n")
|
||||||
|
for _, line := range lines {
|
||||||
|
parts := strings.Fields(line)
|
||||||
|
if len(parts) < 5 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return parts[2] + " " + parts[3], nil
|
||||||
|
}
|
||||||
|
return "", fmt.Errorf("no such model %s in ollama list, std: %s", name, string(stdout))
|
||||||
|
}
|
||||||
+53
-35
@@ -5,6 +5,7 @@ import (
|
|||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@@ -34,9 +35,9 @@ type AppService struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type IAppService interface {
|
type IAppService interface {
|
||||||
PageApp(req request.AppSearch) (interface{}, error)
|
PageApp(ctx *gin.Context, req request.AppSearch) (interface{}, error)
|
||||||
GetAppTags() ([]response.TagDTO, error)
|
GetAppTags(ctx *gin.Context) ([]response.TagDTO, error)
|
||||||
GetApp(key string) (*response.AppDTO, error)
|
GetApp(ctx *gin.Context, key string) (*response.AppDTO, error)
|
||||||
GetAppDetail(appId uint, version, appType string) (response.AppDetailDTO, error)
|
GetAppDetail(appId uint, version, appType string) (response.AppDetailDTO, error)
|
||||||
Install(ctx context.Context, req request.AppInstallCreate) (*model.AppInstall, error)
|
Install(ctx context.Context, req request.AppInstallCreate) (*model.AppInstall, error)
|
||||||
SyncAppListFromRemote() error
|
SyncAppListFromRemote() error
|
||||||
@@ -50,7 +51,7 @@ func NewIAppService() IAppService {
|
|||||||
return &AppService{}
|
return &AppService{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a AppService) PageApp(req request.AppSearch) (interface{}, error) {
|
func (a AppService) PageApp(ctx *gin.Context, req request.AppSearch) (interface{}, error) {
|
||||||
var opts []repo.DBOption
|
var opts []repo.DBOption
|
||||||
opts = append(opts, appRepo.OrderByRecommend())
|
opts = append(opts, appRepo.OrderByRecommend())
|
||||||
if req.Name != "" {
|
if req.Name != "" {
|
||||||
@@ -89,31 +90,24 @@ func (a AppService) PageApp(req request.AppSearch) (interface{}, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var appDTOs []*response.AppDto
|
var appDTOs []*response.AppItem
|
||||||
|
lang := strings.ToLower(common.GetLang(ctx))
|
||||||
for _, ap := range apps {
|
for _, ap := range apps {
|
||||||
appDTO := &response.AppDto{
|
appDTO := &response.AppItem{
|
||||||
ID: ap.ID,
|
ID: ap.ID,
|
||||||
Name: ap.Name,
|
Name: ap.Name,
|
||||||
Key: ap.Key,
|
Key: ap.Key,
|
||||||
Type: ap.Type,
|
Type: ap.Type,
|
||||||
Icon: ap.Icon,
|
Icon: ap.Icon,
|
||||||
ShortDescZh: ap.ShortDescZh,
|
Resource: ap.Resource,
|
||||||
ShortDescEn: ap.ShortDescEn,
|
Limit: ap.Limit,
|
||||||
Resource: ap.Resource,
|
GpuSupport: ap.GpuSupport,
|
||||||
Limit: ap.Limit,
|
|
||||||
}
|
}
|
||||||
|
appDTO.Description = ap.GetDescription(ctx)
|
||||||
appDTOs = append(appDTOs, appDTO)
|
appDTOs = append(appDTOs, appDTO)
|
||||||
appTags, err := appTagRepo.GetByAppId(ap.ID)
|
tags, err := getAppTags(ap.ID, lang)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
return nil, err
|
||||||
}
|
|
||||||
var tagIds []uint
|
|
||||||
for _, at := range appTags {
|
|
||||||
tagIds = append(tagIds, at.TagId)
|
|
||||||
}
|
|
||||||
tags, err := tagRepo.GetByIds(tagIds)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
appDTO.Tags = tags
|
appDTO.Tags = tags
|
||||||
installs, _ := appInstallRepo.ListBy(appInstallRepo.WithAppId(ap.ID))
|
installs, _ := appInstallRepo.ListBy(appInstallRepo.WithAppId(ap.ID))
|
||||||
@@ -125,18 +119,32 @@ func (a AppService) PageApp(req request.AppSearch) (interface{}, error) {
|
|||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a AppService) GetAppTags() ([]response.TagDTO, error) {
|
func (a AppService) GetAppTags(ctx *gin.Context) ([]response.TagDTO, error) {
|
||||||
tags, _ := tagRepo.All()
|
tags, _ := tagRepo.All()
|
||||||
res := make([]response.TagDTO, 0)
|
res := make([]response.TagDTO, 0)
|
||||||
|
lang := strings.ToLower(common.GetLang(ctx))
|
||||||
for _, tag := range tags {
|
for _, tag := range tags {
|
||||||
res = append(res, response.TagDTO{
|
tagDTO := response.TagDTO{
|
||||||
Tag: tag,
|
ID: tag.ID,
|
||||||
})
|
Key: tag.Key,
|
||||||
|
}
|
||||||
|
var translations = make(map[string]string)
|
||||||
|
_ = json.Unmarshal([]byte(tag.Translations), &translations)
|
||||||
|
if name, ok := translations[lang]; ok && name != "" {
|
||||||
|
tagDTO.Name = name
|
||||||
|
} else {
|
||||||
|
if lang == "zh" || lang == "zh-Hant" {
|
||||||
|
tagDTO.Name = tag.Name
|
||||||
|
} else {
|
||||||
|
tagDTO.Name = tag.Key
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res = append(res, tagDTO)
|
||||||
}
|
}
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a AppService) GetApp(key string) (*response.AppDTO, error) {
|
func (a AppService) GetApp(ctx *gin.Context, key string) (*response.AppDTO, error) {
|
||||||
var appDTO response.AppDTO
|
var appDTO response.AppDTO
|
||||||
if key == "postgres" {
|
if key == "postgres" {
|
||||||
key = "postgresql"
|
key = "postgresql"
|
||||||
@@ -146,6 +154,7 @@ func (a AppService) GetApp(key string) (*response.AppDTO, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
appDTO.App = app
|
appDTO.App = app
|
||||||
|
appDTO.App.Description = app.GetDescription(ctx)
|
||||||
details, err := appDetailRepo.GetBy(appDetailRepo.WithAppId(app.ID))
|
details, err := appDetailRepo.GetBy(appDetailRepo.WithAppId(app.ID))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -155,7 +164,12 @@ func (a AppService) GetApp(key string) (*response.AppDTO, error) {
|
|||||||
versionsRaw = append(versionsRaw, detail.Version)
|
versionsRaw = append(versionsRaw, detail.Version)
|
||||||
}
|
}
|
||||||
appDTO.Versions = common.GetSortedVersions(versionsRaw)
|
appDTO.Versions = common.GetSortedVersions(versionsRaw)
|
||||||
|
tags, err := getAppTags(app.ID, strings.ToLower(common.GetLang(ctx)))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
appDTO.GpuSupport = app.GpuSupport
|
||||||
|
appDTO.Tags = tags
|
||||||
return &appDTO, nil
|
return &appDTO, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -252,6 +266,7 @@ func (a AppService) GetAppDetail(appID uint, version, appType string) (response.
|
|||||||
if err := checkLimit(app); err != nil {
|
if err := checkLimit(app); err != nil {
|
||||||
appDetailDTO.Enable = false
|
appDetailDTO.Enable = false
|
||||||
}
|
}
|
||||||
|
appDetailDTO.GpuSupport = app.GpuSupport
|
||||||
return appDetailDTO, nil
|
return appDetailDTO, nil
|
||||||
}
|
}
|
||||||
func (a AppService) GetAppDetailByID(id uint) (*response.AppDetailDTO, error) {
|
func (a AppService) GetAppDetailByID(id uint) (*response.AppDetailDTO, error) {
|
||||||
@@ -296,7 +311,8 @@ func (a AppService) Install(ctx context.Context, req request.AppInstallCreate) (
|
|||||||
err = buserr.WithDetail(constant.Err1PanelNetworkFailed, err.Error(), nil)
|
err = buserr.WithDetail(constant.Err1PanelNetworkFailed, err.Error(), nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if list, _ := appInstallRepo.ListBy(commonRepo.WithByName(req.Name)); len(list) > 0 {
|
|
||||||
|
if list, _ := appInstallRepo.ListBy(commonRepo.WithByLowerName(req.Name)); len(list) > 0 {
|
||||||
err = buserr.New(constant.ErrAppNameExist)
|
err = buserr.New(constant.ErrAppNameExist)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -827,10 +843,11 @@ func (a AppService) SyncAppListFromRemote() (err error) {
|
|||||||
oldAppIds []uint
|
oldAppIds []uint
|
||||||
)
|
)
|
||||||
for _, t := range list.Extra.Tags {
|
for _, t := range list.Extra.Tags {
|
||||||
|
translations, _ := json.Marshal(t.Locales)
|
||||||
tags = append(tags, &model.Tag{
|
tags = append(tags, &model.Tag{
|
||||||
Key: t.Key,
|
Key: t.Key,
|
||||||
Name: t.Name,
|
Translations: string(translations),
|
||||||
Sort: t.Sort,
|
Sort: t.Sort,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
oldApps, err := appRepo.GetBy(appRepo.WithResource(constant.AppResourceRemote))
|
oldApps, err := appRepo.GetBy(appRepo.WithResource(constant.AppResourceRemote))
|
||||||
@@ -848,6 +865,7 @@ func (a AppService) SyncAppListFromRemote() (err error) {
|
|||||||
global.LOG.Infof("Starting synchronization of application details...")
|
global.LOG.Infof("Starting synchronization of application details...")
|
||||||
for _, l := range list.Apps {
|
for _, l := range list.Apps {
|
||||||
app := appsMap[l.AppProperty.Key]
|
app := appsMap[l.AppProperty.Key]
|
||||||
|
app.GpuSupport = l.AppProperty.GpuSupport
|
||||||
|
|
||||||
if l.AppProperty.Version > 0 && common.CompareVersion(strconv.FormatFloat(l.AppProperty.Version, 'f', -1, 64), setting.SystemVersion) {
|
if l.AppProperty.Version > 0 && common.CompareVersion(strconv.FormatFloat(l.AppProperty.Version, 'f', -1, 64), setting.SystemVersion) {
|
||||||
delete(appsMap, l.AppProperty.Key)
|
delete(appsMap, l.AppProperty.Key)
|
||||||
|
|||||||
@@ -750,6 +750,7 @@ func (a *AppInstallService) GetParams(id uint) (*response.AppConfig, error) {
|
|||||||
}
|
}
|
||||||
res.AppContainerConfig = config
|
res.AppContainerConfig = config
|
||||||
res.HostMode = isHostModel(install.DockerCompose)
|
res.HostMode = isHostModel(install.DockerCompose)
|
||||||
|
res.GpuConfig = isGpuConfig(install.DockerCompose)
|
||||||
return &res, nil
|
return &res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -838,6 +839,9 @@ func updateInstallInfoInDB(appKey, appName, param string, value interface{}) err
|
|||||||
"param": strings.ReplaceAll(appInstall.Param, oldVal, newVal),
|
"param": strings.ReplaceAll(appInstall.Param, oldVal, newVal),
|
||||||
"env": strings.ReplaceAll(appInstall.Env, oldVal, newVal),
|
"env": strings.ReplaceAll(appInstall.Env, oldVal, newVal),
|
||||||
}, commonRepo.WithByID(appInstall.ID))
|
}, commonRepo.WithByID(appInstall.ID))
|
||||||
|
if appKey == "mysql" || appKey == "postgresql" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if param == "user-password" {
|
if param == "user-password" {
|
||||||
oldVal = fmt.Sprintf("\"PANEL_DB_USER_PASSWORD\":\"%v\"", appInstall.UserPassword)
|
oldVal = fmt.Sprintf("\"PANEL_DB_USER_PASSWORD\":\"%v\"", appInstall.UserPassword)
|
||||||
|
|||||||
@@ -442,17 +442,14 @@ func deleteLink(ctx context.Context, install *model.AppInstall, deleteDB bool, f
|
|||||||
return appInstallResourceRepo.DeleteBy(ctx, appInstallResourceRepo.WithAppInstallId(install.ID))
|
return appInstallResourceRepo.DeleteBy(ctx, appInstallResourceRepo.WithAppInstallId(install.ID))
|
||||||
}
|
}
|
||||||
|
|
||||||
func getUpgradeCompose(install model.AppInstall, detail model.AppDetail) (string, error) {
|
func handleUpgradeCompose(install model.AppInstall, detail model.AppDetail) (map[string]interface{}, error) {
|
||||||
if detail.DockerCompose == "" {
|
|
||||||
return "", nil
|
|
||||||
}
|
|
||||||
composeMap := make(map[string]interface{})
|
composeMap := make(map[string]interface{})
|
||||||
if err := yaml.Unmarshal([]byte(detail.DockerCompose), &composeMap); err != nil {
|
if err := yaml.Unmarshal([]byte(detail.DockerCompose), &composeMap); err != nil {
|
||||||
return "", err
|
return nil, err
|
||||||
}
|
}
|
||||||
value, ok := composeMap["services"]
|
value, ok := composeMap["services"]
|
||||||
if !ok || value == nil {
|
if !ok || value == nil {
|
||||||
return "", buserr.New(constant.ErrFileParse)
|
return nil, buserr.New("ErrFileParse")
|
||||||
}
|
}
|
||||||
servicesMap := value.(map[string]interface{})
|
servicesMap := value.(map[string]interface{})
|
||||||
if len(servicesMap) == 1 {
|
if len(servicesMap) == 1 {
|
||||||
@@ -470,6 +467,34 @@ func getUpgradeCompose(install model.AppInstall, detail model.AppDetail) (string
|
|||||||
delete(servicesMap, oldServiceName)
|
delete(servicesMap, oldServiceName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
serviceValue := servicesMap[install.ServiceName].(map[string]interface{})
|
||||||
|
|
||||||
|
oldComposeMap := make(map[string]interface{})
|
||||||
|
if err := yaml.Unmarshal([]byte(install.DockerCompose), &oldComposeMap); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
oldValue, ok := oldComposeMap["services"]
|
||||||
|
if !ok || oldValue == nil {
|
||||||
|
return nil, buserr.New("ErrFileParse")
|
||||||
|
}
|
||||||
|
oldValueMap := oldValue.(map[string]interface{})
|
||||||
|
oldServiceValue := oldValueMap[install.ServiceName].(map[string]interface{})
|
||||||
|
if oldServiceValue["deploy"] != nil {
|
||||||
|
serviceValue["deploy"] = oldServiceValue["deploy"]
|
||||||
|
}
|
||||||
|
servicesMap[install.ServiceName] = serviceValue
|
||||||
|
composeMap["services"] = servicesMap
|
||||||
|
return composeMap, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getUpgradeCompose(install model.AppInstall, detail model.AppDetail) (string, error) {
|
||||||
|
if detail.DockerCompose == "" {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
composeMap, err := handleUpgradeCompose(install, detail)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
envs := make(map[string]interface{})
|
envs := make(map[string]interface{})
|
||||||
if err := json.Unmarshal([]byte(install.Env), &envs); err != nil {
|
if err := json.Unmarshal([]byte(install.Env), &envs); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
@@ -1051,6 +1076,8 @@ func getApps(oldApps []model.App, items []dto.AppDefine) map[string]model.App {
|
|||||||
app.Key = key
|
app.Key = key
|
||||||
app.ShortDescZh = config.ShortDescZh
|
app.ShortDescZh = config.ShortDescZh
|
||||||
app.ShortDescEn = config.ShortDescEn
|
app.ShortDescEn = config.ShortDescEn
|
||||||
|
description, _ := json.Marshal(config.Description)
|
||||||
|
app.Description = string(description)
|
||||||
app.Website = config.Website
|
app.Website = config.Website
|
||||||
app.Document = config.Document
|
app.Document = config.Document
|
||||||
app.Github = config.Github
|
app.Github = config.Github
|
||||||
@@ -1150,14 +1177,31 @@ func handleLocalApp(appDir string) (app *model.App, err error) {
|
|||||||
err = buserr.WithMap(constant.ErrFileParseApp, map[string]interface{}{"name": "data.yml", "err": err.Error()}, err)
|
err = buserr.WithMap(constant.ErrFileParseApp, map[string]interface{}{"name": "data.yml", "err": err.Error()}, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
app = &localAppDefine.AppProperty
|
appDefine := localAppDefine.AppProperty
|
||||||
|
app = &model.App{}
|
||||||
|
app.Name = appDefine.Name
|
||||||
|
app.TagsKey = append(appDefine.Tags, "Local")
|
||||||
|
app.Type = appDefine.Type
|
||||||
|
app.CrossVersionUpdate = appDefine.CrossVersionUpdate
|
||||||
|
app.Limit = appDefine.Limit
|
||||||
|
app.Recommend = appDefine.Recommend
|
||||||
|
app.Website = appDefine.Website
|
||||||
|
app.Github = appDefine.Github
|
||||||
|
app.Document = appDefine.Document
|
||||||
|
if appDefine.ShortDescZh != "" {
|
||||||
|
app.ShortDescZh = appDefine.ShortDescZh
|
||||||
|
}
|
||||||
|
if appDefine.ShortDescEn != "" {
|
||||||
|
app.ShortDescEn = appDefine.ShortDescEn
|
||||||
|
}
|
||||||
|
desc, _ := json.Marshal(appDefine.Description)
|
||||||
|
app.Description = string(desc)
|
||||||
|
|
||||||
|
app.Key = "local" + appDefine.Key
|
||||||
app.Resource = constant.AppResourceLocal
|
app.Resource = constant.AppResourceLocal
|
||||||
app.Status = constant.AppNormal
|
app.Status = constant.AppNormal
|
||||||
app.Recommend = 9999
|
app.Recommend = 9999
|
||||||
app.TagsKey = append(app.TagsKey, "Local")
|
readMeByte, err := fileOp.GetContent(path.Join(appDir, "README.md"))
|
||||||
app.Key = "local" + app.Key
|
|
||||||
readMePath := path.Join(appDir, "README.md")
|
|
||||||
readMeByte, err := fileOp.GetContent(readMePath)
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
app.ReadMe = string(readMeByte)
|
app.ReadMe = string(readMeByte)
|
||||||
}
|
}
|
||||||
@@ -1319,9 +1363,10 @@ func handleInstalled(appInstallList []model.AppInstall, updated bool, sync bool)
|
|||||||
Path: installed.GetPath(),
|
Path: installed.GetPath(),
|
||||||
CreatedAt: installed.CreatedAt,
|
CreatedAt: installed.CreatedAt,
|
||||||
App: response.AppDetail{
|
App: response.AppDetail{
|
||||||
Github: installed.App.Github,
|
Github: installed.App.Github,
|
||||||
Website: installed.App.Website,
|
Website: installed.App.Website,
|
||||||
Document: installed.App.Document,
|
Document: installed.App.Document,
|
||||||
|
GpuSupport: installed.App.GpuSupport,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
if updated {
|
if updated {
|
||||||
@@ -1480,6 +1525,20 @@ func addDockerComposeCommonParam(composeMap map[string]interface{}, serviceName
|
|||||||
deploy["resources"] = resource
|
deploy["resources"] = resource
|
||||||
serviceValue["deploy"] = deploy
|
serviceValue["deploy"] = deploy
|
||||||
|
|
||||||
|
if req.GpuConfig {
|
||||||
|
resource["reservations"] = map[string]interface{}{
|
||||||
|
"devices": []map[string]interface{}{
|
||||||
|
{
|
||||||
|
"driver": "nvidia",
|
||||||
|
"count": "all",
|
||||||
|
"capabilities": []string{"gpu"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
delete(resource, "reservations")
|
||||||
|
}
|
||||||
|
|
||||||
ports, ok := serviceValue["ports"].([]interface{})
|
ports, ok := serviceValue["ports"].([]interface{})
|
||||||
if ok {
|
if ok {
|
||||||
for i, port := range ports {
|
for i, port := range ports {
|
||||||
@@ -1581,9 +1640,74 @@ func isHostModel(dockerCompose string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isGpuConfig(dockerCompose string) bool {
|
||||||
|
composeMap := make(map[string]interface{})
|
||||||
|
_ = yaml.Unmarshal([]byte(dockerCompose), &composeMap)
|
||||||
|
services, serviceValid := composeMap["services"].(map[string]interface{})
|
||||||
|
if !serviceValid {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, service := range services {
|
||||||
|
serviceValue := service.(map[string]interface{})
|
||||||
|
deploy := map[string]interface{}{}
|
||||||
|
if de, ok := serviceValue["deploy"]; ok {
|
||||||
|
deploy = de.(map[string]interface{})
|
||||||
|
}
|
||||||
|
resource := map[string]interface{}{}
|
||||||
|
if res, ok := deploy["resources"]; ok {
|
||||||
|
resource = res.(map[string]interface{})
|
||||||
|
}
|
||||||
|
if reservations, ok := resource["reservations"]; ok {
|
||||||
|
reservationsMap := reservations.(map[string]interface{})
|
||||||
|
if _, dOk := reservationsMap["devices"]; dOk {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func RequestDownloadCallBack(downloadCallBackUrl string) {
|
func RequestDownloadCallBack(downloadCallBackUrl string) {
|
||||||
if downloadCallBackUrl == "" {
|
if downloadCallBackUrl == "" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
_, _, _ = httpUtil.HandleGet(downloadCallBackUrl, http.MethodGet, constant.TimeOut5s)
|
_, _, _ = httpUtil.HandleGet(downloadCallBackUrl, http.MethodGet, constant.TimeOut5s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getAppTags(appID uint, lang string) ([]response.TagDTO, error) {
|
||||||
|
appTags, err := appTagRepo.GetByAppId(appID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var tagIds []uint
|
||||||
|
for _, at := range appTags {
|
||||||
|
tagIds = append(tagIds, at.TagId)
|
||||||
|
}
|
||||||
|
tags, err := tagRepo.GetByIds(tagIds)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var res []response.TagDTO
|
||||||
|
for _, t := range tags {
|
||||||
|
if t.Name != "" {
|
||||||
|
tagDTO := response.TagDTO{
|
||||||
|
ID: t.ID,
|
||||||
|
Key: t.Key,
|
||||||
|
Name: t.Name,
|
||||||
|
}
|
||||||
|
res = append(res, tagDTO)
|
||||||
|
} else {
|
||||||
|
var translations = make(map[string]string)
|
||||||
|
_ = json.Unmarshal([]byte(t.Translations), &translations)
|
||||||
|
if name, ok := translations[lang]; ok {
|
||||||
|
tagDTO := response.TagDTO{
|
||||||
|
ID: t.ID,
|
||||||
|
Key: t.Key,
|
||||||
|
Name: name,
|
||||||
|
}
|
||||||
|
res = append(res, tagDTO)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|||||||
+31
-19
@@ -38,16 +38,11 @@ func (u *AuthService) Login(c *gin.Context, info dto.Login, entrance string) (*d
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.WithMessage(constant.ErrRecordNotFound, err.Error())
|
return nil, errors.WithMessage(constant.ErrRecordNotFound, err.Error())
|
||||||
}
|
}
|
||||||
passwordSetting, err := settingRepo.Get(settingRepo.WithByKey("Password"))
|
if nameSetting.Value != info.Name {
|
||||||
if err != nil {
|
|
||||||
return nil, errors.WithMessage(constant.ErrRecordNotFound, err.Error())
|
|
||||||
}
|
|
||||||
pass, err := encrypt.StringDecrypt(passwordSetting.Value)
|
|
||||||
if err != nil {
|
|
||||||
return nil, constant.ErrAuth
|
return nil, constant.ErrAuth
|
||||||
}
|
}
|
||||||
if !hmac.Equal([]byte(info.Password), []byte(pass)) || nameSetting.Value != info.Name {
|
if err = checkPassword(info.Password); err != nil {
|
||||||
return nil, constant.ErrAuth
|
return nil, err
|
||||||
}
|
}
|
||||||
entranceSetting, err := settingRepo.Get(settingRepo.WithByKey("SecurityEntrance"))
|
entranceSetting, err := settingRepo.Get(settingRepo.WithByKey("SecurityEntrance"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -83,17 +78,12 @@ func (u *AuthService) MFALogin(c *gin.Context, info dto.MFALogin, entrance strin
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.WithMessage(constant.ErrRecordNotFound, err.Error())
|
return nil, errors.WithMessage(constant.ErrRecordNotFound, err.Error())
|
||||||
}
|
}
|
||||||
passwordSetting, err := settingRepo.Get(settingRepo.WithByKey("Password"))
|
if nameSetting.Value != info.Name {
|
||||||
if err != nil {
|
|
||||||
return nil, errors.WithMessage(constant.ErrRecordNotFound, err.Error())
|
|
||||||
}
|
|
||||||
pass, err := encrypt.StringDecrypt(passwordSetting.Value)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if !hmac.Equal([]byte(info.Password), []byte(pass)) || nameSetting.Value != info.Name {
|
|
||||||
return nil, constant.ErrAuth
|
return nil, constant.ErrAuth
|
||||||
}
|
}
|
||||||
|
if err = checkPassword(info.Password); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
entranceSetting, err := settingRepo.Get(settingRepo.WithByKey("SecurityEntrance"))
|
entranceSetting, err := settingRepo.Get(settingRepo.WithByKey("SecurityEntrance"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -214,8 +204,30 @@ func (u *AuthService) GetSecurityEntrance() string {
|
|||||||
func (u *AuthService) IsLogin(c *gin.Context) bool {
|
func (u *AuthService) IsLogin(c *gin.Context) bool {
|
||||||
sID, _ := c.Cookie(constant.SessionName)
|
sID, _ := c.Cookie(constant.SessionName)
|
||||||
_, err := global.SESSION.Get(sID)
|
_, err := global.SESSION.Get(sID)
|
||||||
|
return err == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkPassword(password string) error {
|
||||||
|
priKey, _ := settingRepo.Get(settingRepo.WithByKey("PASSWORD_PRIVATE_KEY"))
|
||||||
|
|
||||||
|
privateKey, err := encrypt.ParseRSAPrivateKey(priKey.Value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return err
|
||||||
}
|
}
|
||||||
return true
|
loginPassword, err := encrypt.DecryptPassword(password, privateKey)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
passwordSetting, err := settingRepo.Get(settingRepo.WithByKey("Password"))
|
||||||
|
if err != nil {
|
||||||
|
return errors.WithMessage(constant.ErrRecordNotFound, err.Error())
|
||||||
|
}
|
||||||
|
existPassword, err := encrypt.StringDecrypt(passwordSetting.Value)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !hmac.Equal([]byte(loginPassword), []byte(existPassword)) {
|
||||||
|
return constant.ErrAuth
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"sort"
|
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
@@ -30,7 +29,9 @@ type BackupService struct{}
|
|||||||
type IBackupService interface {
|
type IBackupService interface {
|
||||||
List() ([]dto.BackupInfo, error)
|
List() ([]dto.BackupInfo, error)
|
||||||
SearchRecordsWithPage(search dto.RecordSearch) (int64, []dto.BackupRecords, error)
|
SearchRecordsWithPage(search dto.RecordSearch) (int64, []dto.BackupRecords, error)
|
||||||
|
LoadSize(req dto.RecordSearch) ([]dto.BackupFile, error)
|
||||||
SearchRecordsByCronjobWithPage(search dto.RecordSearchByCronjob) (int64, []dto.BackupRecords, error)
|
SearchRecordsByCronjobWithPage(search dto.RecordSearchByCronjob) (int64, []dto.BackupRecords, error)
|
||||||
|
LoadSizeByCronjob(req dto.RecordSearchByCronjob) ([]dto.BackupFile, error)
|
||||||
LoadOneDriveInfo() (dto.OneDriveInfo, error)
|
LoadOneDriveInfo() (dto.OneDriveInfo, error)
|
||||||
DownloadRecord(info dto.DownloadRecord) (string, error)
|
DownloadRecord(info dto.DownloadRecord) (string, error)
|
||||||
Create(backupDto dto.BackupOperate) error
|
Create(backupDto dto.BackupOperate) error
|
||||||
@@ -94,11 +95,29 @@ func (u *BackupService) SearchRecordsWithPage(search dto.RecordSearch) (int64, [
|
|||||||
return 0, nil, err
|
return 0, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
datas, err := u.loadRecordSize(records)
|
var list []dto.BackupRecords
|
||||||
sort.Slice(datas, func(i, j int) bool {
|
for _, item := range records {
|
||||||
return datas[i].CreatedAt.After(datas[j].CreatedAt)
|
var itemRecord dto.BackupRecords
|
||||||
})
|
if err := copier.Copy(&itemRecord, &item); err != nil {
|
||||||
return total, datas, err
|
continue
|
||||||
|
}
|
||||||
|
list = append(list, itemRecord)
|
||||||
|
}
|
||||||
|
return total, list, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *BackupService) LoadSize(req dto.RecordSearch) ([]dto.BackupFile, error) {
|
||||||
|
_, records, err := backupRepo.PageRecord(
|
||||||
|
req.Page, req.PageSize,
|
||||||
|
commonRepo.WithOrderBy("created_at desc"),
|
||||||
|
commonRepo.WithByName(req.Name),
|
||||||
|
commonRepo.WithByType(req.Type),
|
||||||
|
backupRepo.WithByDetailName(req.DetailName),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return u.loadRecordSize(records)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *BackupService) ListAppRecords(name, detailName, fileName string) ([]model.BackupRecord, error) {
|
func (u *BackupService) ListAppRecords(name, detailName, fileName string) ([]model.BackupRecord, error) {
|
||||||
@@ -125,11 +144,27 @@ func (u *BackupService) SearchRecordsByCronjobWithPage(search dto.RecordSearchBy
|
|||||||
return 0, nil, err
|
return 0, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
datas, err := u.loadRecordSize(records)
|
var list []dto.BackupRecords
|
||||||
sort.Slice(datas, func(i, j int) bool {
|
for _, item := range records {
|
||||||
return datas[i].CreatedAt.After(datas[j].CreatedAt)
|
var itemRecord dto.BackupRecords
|
||||||
})
|
if err := copier.Copy(&itemRecord, &item); err != nil {
|
||||||
return total, datas, err
|
continue
|
||||||
|
}
|
||||||
|
list = append(list, itemRecord)
|
||||||
|
}
|
||||||
|
return total, list, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *BackupService) LoadSizeByCronjob(req dto.RecordSearchByCronjob) ([]dto.BackupFile, error) {
|
||||||
|
_, records, err := backupRepo.PageRecord(
|
||||||
|
req.Page, req.PageSize,
|
||||||
|
commonRepo.WithOrderBy("created_at desc"),
|
||||||
|
backupRepo.WithByCronID(req.CronjobID),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return u.loadRecordSize(records)
|
||||||
}
|
}
|
||||||
|
|
||||||
type loadSizeHelper struct {
|
type loadSizeHelper struct {
|
||||||
@@ -378,9 +413,9 @@ func (u *BackupService) Update(req dto.BackupOperate) error {
|
|||||||
if strings.HasSuffix(dirStr, "/") && dirStr != "/" {
|
if strings.HasSuffix(dirStr, "/") && dirStr != "/" {
|
||||||
dirStr = dirStr[:strings.LastIndex(dirStr, "/")]
|
dirStr = dirStr[:strings.LastIndex(dirStr, "/")]
|
||||||
}
|
}
|
||||||
if err := copyDir(oldDir, dirStr); err != nil {
|
if err := changeLocalBackup(oldDir, dirStr); err != nil {
|
||||||
_ = backupRepo.Update(req.ID, map[string]interface{}{"vars": oldVars})
|
_ = backupRepo.Update(req.ID, map[string]interface{}{"vars": oldVars})
|
||||||
return err
|
return fmt.Errorf("copy dir from %s to %s failed, err: %v", oldDir, dirStr, err)
|
||||||
}
|
}
|
||||||
global.CONF.System.Backup = dirStr
|
global.CONF.System.Backup = dirStr
|
||||||
}
|
}
|
||||||
@@ -482,49 +517,41 @@ func (u *BackupService) loadAccessToken(backup *model.BackupAccount) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *BackupService) loadRecordSize(records []model.BackupRecord) ([]dto.BackupRecords, error) {
|
func (u *BackupService) loadRecordSize(records []model.BackupRecord) ([]dto.BackupFile, error) {
|
||||||
var datas []dto.BackupRecords
|
data := make([]dto.BackupFile, len(records))
|
||||||
clientMap := make(map[string]loadSizeHelper)
|
clientMap := make(map[string]loadSizeHelper)
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
for i := 0; i < len(records); i++ {
|
for i := 0; i < len(records); i++ {
|
||||||
var item dto.BackupRecords
|
data[i].ID = records[i].ID
|
||||||
if err := copier.Copy(&item, &records[i]); err != nil {
|
data[i].Name = records[i].FileName
|
||||||
return nil, errors.WithMessage(constant.ErrStructTransform, err.Error())
|
|
||||||
}
|
|
||||||
itemPath := path.Join(records[i].FileDir, records[i].FileName)
|
itemPath := path.Join(records[i].FileDir, records[i].FileName)
|
||||||
if _, ok := clientMap[records[i].Source]; !ok {
|
if _, ok := clientMap[records[i].Source]; !ok {
|
||||||
backup, err := backupRepo.Get(commonRepo.WithByType(records[i].Source))
|
backup, err := backupRepo.Get(commonRepo.WithByType(records[i].Source))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
global.LOG.Errorf("load backup model %s from db failed, err: %v", records[i].Source, err)
|
global.LOG.Errorf("load backup model %s from db failed, err: %v", records[i].Source, err)
|
||||||
clientMap[records[i].Source] = loadSizeHelper{}
|
clientMap[records[i].Source] = loadSizeHelper{}
|
||||||
datas = append(datas, item)
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
client, err := u.NewClient(&backup)
|
client, err := u.NewClient(&backup)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
global.LOG.Errorf("load backup client %s from db failed, err: %v", records[i].Source, err)
|
global.LOG.Errorf("load backup client %s from db failed, err: %v", records[i].Source, err)
|
||||||
clientMap[records[i].Source] = loadSizeHelper{}
|
clientMap[records[i].Source] = loadSizeHelper{}
|
||||||
datas = append(datas, item)
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
item.Size, _ = client.Size(path.Join(strings.TrimLeft(backup.BackupPath, "/"), itemPath))
|
data[i].Size, _ = client.Size(path.Join(strings.TrimLeft(backup.BackupPath, "/"), itemPath))
|
||||||
datas = append(datas, item)
|
|
||||||
clientMap[records[i].Source] = loadSizeHelper{backupPath: strings.TrimLeft(backup.BackupPath, "/"), client: client, isOk: true}
|
clientMap[records[i].Source] = loadSizeHelper{backupPath: strings.TrimLeft(backup.BackupPath, "/"), client: client, isOk: true}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if clientMap[records[i].Source].isOk {
|
if clientMap[records[i].Source].isOk {
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func(index int) {
|
go func(index int) {
|
||||||
item.Size, _ = clientMap[records[index].Source].client.Size(path.Join(clientMap[records[index].Source].backupPath, itemPath))
|
data[i].Size, _ = clientMap[records[index].Source].client.Size(path.Join(clientMap[records[index].Source].backupPath, itemPath))
|
||||||
datas = append(datas, item)
|
|
||||||
wg.Done()
|
wg.Done()
|
||||||
}(i)
|
}(i)
|
||||||
} else {
|
|
||||||
datas = append(datas, item)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
return datas, nil
|
return data, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadLocalDir() (string, error) {
|
func loadLocalDir() (string, error) {
|
||||||
@@ -650,3 +677,44 @@ func (u *BackupService) Run() {
|
|||||||
}).Error
|
}).Error
|
||||||
global.LOG.Info("Successfully refreshed OneDrive token.")
|
global.LOG.Info("Successfully refreshed OneDrive token.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func changeLocalBackup(oldPath, newPath string) error {
|
||||||
|
fileOp := fileUtils.NewFileOp()
|
||||||
|
if fileOp.Stat(path.Join(oldPath, "app")) {
|
||||||
|
if err := fileOp.CopyDir(path.Join(oldPath, "app"), newPath); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if fileOp.Stat(path.Join(oldPath, "database")) {
|
||||||
|
if err := fileOp.CopyDir(path.Join(oldPath, "database"), newPath); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if fileOp.Stat(path.Join(oldPath, "directory")) {
|
||||||
|
if err := fileOp.CopyDir(path.Join(oldPath, "directory"), newPath); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if fileOp.Stat(path.Join(oldPath, "system_snapshot")) {
|
||||||
|
if err := fileOp.CopyDir(path.Join(oldPath, "system_snapshot"), newPath); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if fileOp.Stat(path.Join(oldPath, "website")) {
|
||||||
|
if err := fileOp.CopyDir(path.Join(oldPath, "website"), newPath); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if fileOp.Stat(path.Join(oldPath, "log")) {
|
||||||
|
if err := fileOp.CopyDir(path.Join(oldPath, "log"), newPath); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ = fileOp.RmRf(path.Join(oldPath, "app"))
|
||||||
|
_ = fileOp.RmRf(path.Join(oldPath, "database"))
|
||||||
|
_ = fileOp.RmRf(path.Join(oldPath, "directory"))
|
||||||
|
_ = fileOp.RmRf(path.Join(oldPath, "system_snapshot"))
|
||||||
|
_ = fileOp.RmRf(path.Join(oldPath, "website"))
|
||||||
|
_ = fileOp.RmRf(path.Join(oldPath, "log"))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,13 +2,14 @@ package service
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||||
@@ -169,8 +170,9 @@ func handleMysqlRecover(req dto.CommonRecover, isRollback bool) error {
|
|||||||
Timeout: 300,
|
Timeout: 300,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
global.LOG.Errorf("rollback mysql db %s from %s failed, err: %v", req.DetailName, rollbackFile, err)
|
global.LOG.Errorf("rollback mysql db %s from %s failed, err: %v", req.DetailName, rollbackFile, err)
|
||||||
|
} else {
|
||||||
|
global.LOG.Infof("rollback mysql db %s from %s successful", req.DetailName, rollbackFile)
|
||||||
}
|
}
|
||||||
global.LOG.Infof("rollback mysql db %s from %s successful", req.DetailName, rollbackFile)
|
|
||||||
_ = os.RemoveAll(rollbackFile)
|
_ = os.RemoveAll(rollbackFile)
|
||||||
} else {
|
} else {
|
||||||
_ = os.RemoveAll(rollbackFile)
|
_ = os.RemoveAll(rollbackFile)
|
||||||
@@ -186,6 +188,7 @@ func handleMysqlRecover(req dto.CommonRecover, isRollback bool) error {
|
|||||||
|
|
||||||
Timeout: 300,
|
Timeout: 300,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
|
global.LOG.Errorf("recover mysql db %s from %s failed, err: %v", req.DetailName, req.File, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
isOk = true
|
isOk = true
|
||||||
|
|||||||
@@ -2,13 +2,14 @@ package service
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
||||||
pgclient "github.com/1Panel-dev/1Panel/backend/utils/postgresql/client"
|
pgclient "github.com/1Panel-dev/1Panel/backend/utils/postgresql/client"
|
||||||
@@ -157,8 +158,9 @@ func handlePostgresqlRecover(req dto.CommonRecover, isRollback bool) error {
|
|||||||
Timeout: 300,
|
Timeout: 300,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
global.LOG.Errorf("rollback postgresql db %s from %s failed, err: %v", req.DetailName, rollbackFile, err)
|
global.LOG.Errorf("rollback postgresql db %s from %s failed, err: %v", req.DetailName, rollbackFile, err)
|
||||||
|
} else {
|
||||||
|
global.LOG.Infof("rollback postgresql db %s from %s successful", req.DetailName, rollbackFile)
|
||||||
}
|
}
|
||||||
global.LOG.Infof("rollback postgresql db %s from %s successful", req.DetailName, rollbackFile)
|
|
||||||
_ = os.RemoveAll(rollbackFile)
|
_ = os.RemoveAll(rollbackFile)
|
||||||
} else {
|
} else {
|
||||||
_ = os.RemoveAll(rollbackFile)
|
_ = os.RemoveAll(rollbackFile)
|
||||||
@@ -171,6 +173,7 @@ func handlePostgresqlRecover(req dto.CommonRecover, isRollback bool) error {
|
|||||||
Username: dbInfo.Username,
|
Username: dbInfo.Username,
|
||||||
Timeout: 300,
|
Timeout: 300,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
|
global.LOG.Errorf("recover postgresql db %s from %s failed, err: %v", req.DetailName, req.File, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
isOk = true
|
isOk = true
|
||||||
|
|||||||
+103
-129
@@ -1,7 +1,6 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
@@ -28,14 +27,14 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
clamServiceNameCentOs = "clamd@scan.service"
|
clamServiceKey = "clam"
|
||||||
clamServiceNameUbuntu = "clamav-daemon.service"
|
freshClamServiceKey = "freshclam"
|
||||||
freshClamService = "clamav-freshclam.service"
|
resultDir = "clamav"
|
||||||
resultDir = "clamav"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type ClamService struct {
|
type ClamService struct {
|
||||||
serviceName string
|
serviceName string
|
||||||
|
freshClamService string
|
||||||
}
|
}
|
||||||
|
|
||||||
type IClamService interface {
|
type IClamService interface {
|
||||||
@@ -63,23 +62,32 @@ func (c *ClamService) LoadBaseInfo() (dto.ClamBaseInfo, error) {
|
|||||||
var baseInfo dto.ClamBaseInfo
|
var baseInfo dto.ClamBaseInfo
|
||||||
baseInfo.Version = "-"
|
baseInfo.Version = "-"
|
||||||
baseInfo.FreshVersion = "-"
|
baseInfo.FreshVersion = "-"
|
||||||
exist1, _ := systemctl.IsExist(clamServiceNameCentOs)
|
clamSvc, err := systemctl.GetServiceName(clamServiceKey)
|
||||||
if exist1 {
|
if err != nil {
|
||||||
c.serviceName = clamServiceNameCentOs
|
baseInfo.IsExist = false
|
||||||
baseInfo.IsExist = true
|
return baseInfo, nil
|
||||||
baseInfo.IsActive, _ = systemctl.IsActive(clamServiceNameCentOs)
|
|
||||||
}
|
}
|
||||||
exist2, _ := systemctl.IsExist(clamServiceNameUbuntu)
|
c.serviceName = clamSvc
|
||||||
if exist2 {
|
isExist, err := systemctl.IsExist(c.serviceName)
|
||||||
c.serviceName = clamServiceNameUbuntu
|
if err != nil {
|
||||||
baseInfo.IsExist = true
|
baseInfo.IsExist = false
|
||||||
baseInfo.IsActive, _ = systemctl.IsActive(clamServiceNameUbuntu)
|
|
||||||
}
|
}
|
||||||
freshExist, _ := systemctl.IsExist(freshClamService)
|
baseInfo.IsExist = isExist
|
||||||
if freshExist {
|
baseInfo.IsActive, _ = systemctl.IsActive(clamSvc)
|
||||||
baseInfo.FreshIsExist = true
|
|
||||||
baseInfo.FreshIsActive, _ = systemctl.IsActive(freshClamService)
|
freshSvc, err := systemctl.GetServiceName(freshClamServiceKey)
|
||||||
|
if err != nil {
|
||||||
|
baseInfo.FreshIsExist = false
|
||||||
|
return baseInfo, nil
|
||||||
}
|
}
|
||||||
|
c.freshClamService = freshSvc
|
||||||
|
freshisExist, err := systemctl.IsExist(c.freshClamService)
|
||||||
|
if err != nil {
|
||||||
|
baseInfo.FreshIsExist = false
|
||||||
|
}
|
||||||
|
baseInfo.FreshIsExist = freshisExist
|
||||||
|
baseInfo.FreshIsActive, _ = systemctl.IsActive(freshSvc)
|
||||||
|
|
||||||
if !cmd.Which("clamdscan") {
|
if !cmd.Which("clamdscan") {
|
||||||
baseInfo.IsActive = false
|
baseInfo.IsActive = false
|
||||||
}
|
}
|
||||||
@@ -110,22 +118,27 @@ func (c *ClamService) LoadBaseInfo() (dto.ClamBaseInfo, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *ClamService) Operate(operate string) error {
|
func (c *ClamService) Operate(operate string) error {
|
||||||
|
var err error
|
||||||
switch operate {
|
switch operate {
|
||||||
case "start", "restart", "stop":
|
case "start":
|
||||||
stdout, err := cmd.Execf("systemctl %s %s", operate, c.serviceName)
|
err = systemctl.Start(c.serviceName)
|
||||||
if err != nil {
|
case "stop":
|
||||||
return fmt.Errorf("%s the %s failed, err: %s", operate, c.serviceName, stdout)
|
err = systemctl.Stop(c.serviceName)
|
||||||
}
|
case "restart":
|
||||||
return nil
|
err = systemctl.Restart(c.serviceName)
|
||||||
case "fresh-start", "fresh-restart", "fresh-stop":
|
case "fresh-start":
|
||||||
stdout, err := cmd.Execf("systemctl %s %s", strings.TrimPrefix(operate, "fresh-"), freshClamService)
|
err = systemctl.Start(c.freshClamService)
|
||||||
if err != nil {
|
case "fresh-stop":
|
||||||
return fmt.Errorf("%s the %s failed, err: %s", operate, c.serviceName, stdout)
|
err = systemctl.Stop(c.freshClamService)
|
||||||
}
|
case "fresh-restart":
|
||||||
return nil
|
err = systemctl.Restart(c.freshClamService)
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("not support such operation: %v", operate)
|
return fmt.Errorf("unsupported operation: %s", operate)
|
||||||
}
|
}
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("%s %s failed: %v", operate, c.serviceName, err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ClamService) SearchWithPage(req dto.SearchClamWithPage) (int64, interface{}, error) {
|
func (c *ClamService) SearchWithPage(req dto.SearchClamWithPage) (int64, interface{}, error) {
|
||||||
@@ -432,102 +445,80 @@ func (c *ClamService) LoadFile(req dto.ClamFileReq) (string, error) {
|
|||||||
filePath := ""
|
filePath := ""
|
||||||
switch req.Name {
|
switch req.Name {
|
||||||
case "clamd":
|
case "clamd":
|
||||||
if c.serviceName == clamServiceNameUbuntu {
|
filePath = c.getConfigPath("clamd")
|
||||||
filePath = "/etc/clamav/clamd.conf"
|
|
||||||
} else {
|
|
||||||
filePath = "/etc/clamd.d/scan.conf"
|
|
||||||
}
|
|
||||||
case "clamd-log":
|
case "clamd-log":
|
||||||
filePath = c.loadLogPath("clamd-log")
|
filePath = c.loadLogPath("clamd-log")
|
||||||
if len(filePath) != 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if c.serviceName == clamServiceNameUbuntu {
|
|
||||||
filePath = "/var/log/clamav/clamav.log"
|
|
||||||
} else {
|
|
||||||
filePath = "/var/log/clamd.scan"
|
|
||||||
}
|
|
||||||
case "freshclam":
|
case "freshclam":
|
||||||
if c.serviceName == clamServiceNameUbuntu {
|
filePath = c.getConfigPath("freshclam")
|
||||||
filePath = "/etc/clamav/freshclam.conf"
|
|
||||||
} else {
|
|
||||||
filePath = "/etc/freshclam.conf"
|
|
||||||
}
|
|
||||||
case "freshclam-log":
|
case "freshclam-log":
|
||||||
filePath = c.loadLogPath("freshclam-log")
|
filePath = c.loadLogPath("freshclam-log")
|
||||||
if len(filePath) != 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if c.serviceName == clamServiceNameUbuntu {
|
|
||||||
filePath = "/var/log/clamav/freshclam.log"
|
|
||||||
} else {
|
|
||||||
filePath = "/var/log/freshclam.log"
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
return "", fmt.Errorf("not support such type")
|
return "", fmt.Errorf("unsupported file type")
|
||||||
}
|
}
|
||||||
if _, err := os.Stat(filePath); err != nil {
|
|
||||||
|
content, err := systemctl.ViewConfig(filePath, systemctl.ConfigOption{TailLines: req.Tail})
|
||||||
|
if err != nil {
|
||||||
return "", buserr.New("ErrHttpReqNotFound")
|
return "", buserr.New("ErrHttpReqNotFound")
|
||||||
}
|
}
|
||||||
var tail string
|
return content, nil
|
||||||
if req.Tail != "0" {
|
|
||||||
tail = req.Tail
|
|
||||||
} else {
|
|
||||||
tail = "+1"
|
|
||||||
}
|
|
||||||
cmd := exec.Command("tail", "-n", tail, filePath)
|
|
||||||
stdout, err := cmd.CombinedOutput()
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("tail -n %v failed, err: %v", req.Tail, err)
|
|
||||||
}
|
|
||||||
return string(stdout), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ClamService) UpdateFile(req dto.UpdateByNameAndFile) error {
|
func (c *ClamService) UpdateFile(req dto.UpdateByNameAndFile) error {
|
||||||
filePath := ""
|
var (
|
||||||
service := ""
|
filePath string
|
||||||
|
service string
|
||||||
|
)
|
||||||
|
|
||||||
switch req.Name {
|
switch req.Name {
|
||||||
case "clamd":
|
case "clamd":
|
||||||
if c.serviceName == clamServiceNameUbuntu {
|
filePath = c.getConfigPath("clamd")
|
||||||
service = clamServiceNameUbuntu
|
service = c.serviceName
|
||||||
filePath = "/etc/clamav/clamd.conf"
|
|
||||||
} else {
|
|
||||||
service = clamServiceNameCentOs
|
|
||||||
filePath = "/etc/clamd.d/scan.conf"
|
|
||||||
}
|
|
||||||
case "freshclam":
|
case "freshclam":
|
||||||
if c.serviceName == clamServiceNameUbuntu {
|
filePath = c.getConfigPath("freshclam")
|
||||||
filePath = "/etc/clamav/freshclam.conf"
|
service = c.freshClamService
|
||||||
} else {
|
|
||||||
filePath = "/etc/freshclam.conf"
|
|
||||||
}
|
|
||||||
service = "clamav-freshclam.service"
|
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("not support such type")
|
return fmt.Errorf("unsupported file type")
|
||||||
}
|
}
|
||||||
|
|
||||||
file, err := os.OpenFile(filePath, os.O_WRONLY|os.O_TRUNC, 0640)
|
file, err := os.OpenFile(filePath, os.O_WRONLY|os.O_TRUNC, 0640)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
write := bufio.NewWriter(file)
|
|
||||||
_, _ = write.WriteString(req.File)
|
|
||||||
write.Flush()
|
|
||||||
|
|
||||||
_ = systemctl.Restart(service)
|
if _, err := file.WriteString(req.File); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := systemctl.Restart(service); err != nil {
|
||||||
|
return fmt.Errorf("restart %s failed: %v", service, err)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *ClamService) getConfigPath(confType string) string {
|
||||||
|
switch confType {
|
||||||
|
case "clamd":
|
||||||
|
if _, err := os.Stat("/etc/clamav/clamd.conf"); err == nil {
|
||||||
|
return "/etc/clamav/clamd.conf"
|
||||||
|
}
|
||||||
|
return "/etc/clamd.d/scan.conf"
|
||||||
|
case "freshclam":
|
||||||
|
if _, err := os.Stat("/etc/clamav/freshclam.conf"); err == nil {
|
||||||
|
return "/etc/clamav/freshclam.conf"
|
||||||
|
}
|
||||||
|
return "/etc/freshclam.conf"
|
||||||
|
default:
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func StopAllCronJob(withCheck bool) bool {
|
func StopAllCronJob(withCheck bool) bool {
|
||||||
if withCheck {
|
if withCheck {
|
||||||
isActive := false
|
isActive := false
|
||||||
exist1, _ := systemctl.IsExist(clamServiceNameCentOs)
|
isexist, _ := systemctl.IsExist(clamServiceKey)
|
||||||
if exist1 {
|
if isexist {
|
||||||
isActive, _ = systemctl.IsActive(clamServiceNameCentOs)
|
isActive, _ = systemctl.IsActive(clamServiceKey)
|
||||||
}
|
|
||||||
exist2, _ := systemctl.IsExist(clamServiceNameUbuntu)
|
|
||||||
if exist2 {
|
|
||||||
isActive, _ = systemctl.IsActive(clamServiceNameUbuntu)
|
|
||||||
}
|
}
|
||||||
if isActive {
|
if isActive {
|
||||||
return false
|
return false
|
||||||
@@ -590,42 +581,25 @@ func loadResultFromLog(pathItem string) dto.ClamLog {
|
|||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
func (c *ClamService) loadLogPath(name string) string {
|
func (c *ClamService) loadLogPath(name string) string {
|
||||||
confPath := ""
|
configKey := "clamd"
|
||||||
if name == "clamd-log" {
|
searchPrefix := "LogFile "
|
||||||
if c.serviceName == clamServiceNameUbuntu {
|
if name != "clamd-log" {
|
||||||
confPath = "/etc/clamav/clamd.conf"
|
configKey = "freshclam"
|
||||||
} else {
|
searchPrefix = "UpdateLogFile "
|
||||||
confPath = "/etc/clamd.d/scan.conf"
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if c.serviceName == clamServiceNameUbuntu {
|
|
||||||
confPath = "/etc/clamav/freshclam.conf"
|
|
||||||
} else {
|
|
||||||
confPath = "/etc/freshclam.conf"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if _, err := os.Stat(confPath); err != nil {
|
|
||||||
return ""
|
|
||||||
}
|
}
|
||||||
|
confPath := c.getConfigPath(configKey)
|
||||||
|
|
||||||
content, err := os.ReadFile(confPath)
|
content, err := os.ReadFile(confPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
global.LOG.Debugf("Failed to read %s config: %v", configKey, err)
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
lines := strings.Split(string(content), "\n")
|
|
||||||
if name == "clamd-log" {
|
for _, line := range strings.Split(string(content), "\n") {
|
||||||
for _, line := range lines {
|
if strings.HasPrefix(line, searchPrefix) {
|
||||||
if strings.HasPrefix(line, "LogFile ") {
|
return strings.TrimSpace(strings.TrimPrefix(line, searchPrefix))
|
||||||
return strings.Trim(strings.ReplaceAll(line, "LogFile ", ""), " ")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for _, line := range lines {
|
|
||||||
if strings.HasPrefix(line, "UpdateLogFile ") {
|
|
||||||
return strings.Trim(strings.ReplaceAll(line, "UpdateLogFile ", ""), " ")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -255,14 +255,14 @@ func (u *ContainerService) ContainerListStats() ([]dto.ContainerListStats, error
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var datas []dto.ContainerListStats
|
datas := make([]dto.ContainerListStats, len(list))
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
wg.Add(len(list))
|
wg.Add(len(list))
|
||||||
for i := 0; i < len(list); i++ {
|
for i := 0; i < len(list); i++ {
|
||||||
go func(item types.Container) {
|
go func(index int, item types.Container) {
|
||||||
datas = append(datas, loadCpuAndMem(client, item.ID))
|
datas[index] = loadCpuAndMem(client, item.ID)
|
||||||
wg.Done()
|
wg.Done()
|
||||||
}(list[i])
|
}(i, list[i])
|
||||||
}
|
}
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
return datas, nil
|
return datas, nil
|
||||||
@@ -450,12 +450,14 @@ func (u *ContainerService) ContainerInfo(req dto.OperationWithName) (*dto.Contai
|
|||||||
networkSettings := oldContainer.NetworkSettings
|
networkSettings := oldContainer.NetworkSettings
|
||||||
bridgeNetworkSettings := networkSettings.Networks[data.Network]
|
bridgeNetworkSettings := networkSettings.Networks[data.Network]
|
||||||
if bridgeNetworkSettings.IPAMConfig != nil {
|
if bridgeNetworkSettings.IPAMConfig != nil {
|
||||||
ipv4Address := bridgeNetworkSettings.IPAMConfig.IPv4Address
|
if data.Network != "bridge" {
|
||||||
data.Ipv4 = ipv4Address
|
data.Ipv4 = bridgeNetworkSettings.IPAMConfig.IPv4Address
|
||||||
ipv6Address := bridgeNetworkSettings.IPAMConfig.IPv6Address
|
data.Ipv6 = bridgeNetworkSettings.IPAMConfig.IPv6Address
|
||||||
data.Ipv6 = ipv6Address
|
}
|
||||||
} else {
|
} else {
|
||||||
data.Ipv4 = bridgeNetworkSettings.IPAddress
|
if data.Network != "bridge" {
|
||||||
|
data.Ipv4 = bridgeNetworkSettings.IPAddress
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data.Cmd = oldContainer.Config.Cmd
|
data.Cmd = oldContainer.Config.Cmd
|
||||||
@@ -556,10 +558,7 @@ func (u *ContainerService) ContainerUpgrade(req dto.ContainerUpgrade) error {
|
|||||||
hostConf := oldContainer.HostConfig
|
hostConf := oldContainer.HostConfig
|
||||||
var networkConf network.NetworkingConfig
|
var networkConf network.NetworkingConfig
|
||||||
if oldContainer.NetworkSettings != nil {
|
if oldContainer.NetworkSettings != nil {
|
||||||
for networkKey := range oldContainer.NetworkSettings.Networks {
|
networkConf.EndpointsConfig = oldContainer.NetworkSettings.Networks
|
||||||
networkConf.EndpointsConfig = map[string]*network.EndpointSettings{networkKey: {}}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if err := client.ContainerRemove(ctx, req.Name, container.RemoveOptions{Force: true}); err != nil {
|
if err := client.ContainerRemove(ctx, req.Name, container.RemoveOptions{Force: true}); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -937,15 +936,27 @@ func calculateCPUPercentUnix(stats *types.StatsJSON) float64 {
|
|||||||
}
|
}
|
||||||
return cpuPercent
|
return cpuPercent
|
||||||
}
|
}
|
||||||
|
|
||||||
func calculateMemPercentUnix(memStats types.MemoryStats) float64 {
|
func calculateMemPercentUnix(memStats types.MemoryStats) float64 {
|
||||||
memPercent := 0.0
|
memPercent := 0.0
|
||||||
memUsage := float64(memStats.Usage)
|
memUsage := calculateMemUsageUnixNoCache(memStats)
|
||||||
memLimit := float64(memStats.Limit)
|
memLimit := memStats.Limit
|
||||||
if memUsage > 0.0 && memLimit > 0.0 {
|
if memUsage > 0.0 && memLimit > 0.0 {
|
||||||
memPercent = (memUsage / memLimit) * 100.0
|
memPercent = (float64(memUsage) / float64(memLimit)) * 100.0
|
||||||
}
|
}
|
||||||
return memPercent
|
return memPercent
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func calculateMemUsageUnixNoCache(mem types.MemoryStats) uint64 {
|
||||||
|
if v, isCgroup1 := mem.Stats["total_inactive_file"]; isCgroup1 && v < mem.Usage {
|
||||||
|
return mem.Usage - v
|
||||||
|
}
|
||||||
|
if v := mem.Stats["inactive_file"]; v < mem.Usage {
|
||||||
|
return mem.Usage - v
|
||||||
|
}
|
||||||
|
return mem.Usage
|
||||||
|
}
|
||||||
|
|
||||||
func calculateBlockIO(blkio types.BlkioStats) (blkRead float64, blkWrite float64) {
|
func calculateBlockIO(blkio types.BlkioStats) (blkRead float64, blkWrite float64) {
|
||||||
for _, bioEntry := range blkio.IoServiceBytesRecursive {
|
for _, bioEntry := range blkio.IoServiceBytesRecursive {
|
||||||
switch strings.ToLower(bioEntry.Op) {
|
switch strings.ToLower(bioEntry.Op) {
|
||||||
@@ -1063,7 +1074,7 @@ func loadCpuAndMem(client *client.Client, container string) dto.ContainerListSta
|
|||||||
data.PercpuUsage = len(stats.CPUStats.CPUUsage.PercpuUsage)
|
data.PercpuUsage = len(stats.CPUStats.CPUUsage.PercpuUsage)
|
||||||
|
|
||||||
data.MemoryCache = stats.MemoryStats.Stats["cache"]
|
data.MemoryCache = stats.MemoryStats.Stats["cache"]
|
||||||
data.MemoryUsage = stats.MemoryStats.Usage
|
data.MemoryUsage = calculateMemUsageUnixNoCache(stats.MemoryStats)
|
||||||
data.MemoryLimit = stats.MemoryStats.Limit
|
data.MemoryLimit = stats.MemoryStats.Limit
|
||||||
|
|
||||||
data.MemoryPercent = calculateMemPercentUnix(stats.MemoryStats)
|
data.MemoryPercent = calculateMemPercentUnix(stats.MemoryStats)
|
||||||
@@ -1183,9 +1194,10 @@ func loadConfigInfo(isCreate bool, req dto.ContainerOperate, oldContainer *types
|
|||||||
for _, volume := range req.Volumes {
|
for _, volume := range req.Volumes {
|
||||||
if volume.Type == "volume" {
|
if volume.Type == "volume" {
|
||||||
hostConf.Mounts = append(hostConf.Mounts, mount.Mount{
|
hostConf.Mounts = append(hostConf.Mounts, mount.Mount{
|
||||||
Type: mount.Type(volume.Type),
|
Type: mount.Type(volume.Type),
|
||||||
Source: volume.SourceDir,
|
Source: volume.SourceDir,
|
||||||
Target: volume.ContainerDir,
|
Target: volume.ContainerDir,
|
||||||
|
ReadOnly: volume.Mode == "ro",
|
||||||
})
|
})
|
||||||
config.Volumes[volume.ContainerDir] = struct{}{}
|
config.Volumes[volume.ContainerDir] = struct{}{}
|
||||||
} else {
|
} else {
|
||||||
@@ -1200,10 +1212,7 @@ func reCreateAfterUpdate(name string, client *client.Client, config *container.C
|
|||||||
|
|
||||||
var oldNetworkConf network.NetworkingConfig
|
var oldNetworkConf network.NetworkingConfig
|
||||||
if networkConf != nil {
|
if networkConf != nil {
|
||||||
for networkKey := range networkConf.Networks {
|
oldNetworkConf.EndpointsConfig = networkConf.Networks
|
||||||
oldNetworkConf.EndpointsConfig = map[string]*network.EndpointSettings{networkKey: {}}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
oldContainer, err := client.ContainerCreate(ctx, config, hostConf, &oldNetworkConf, &v1.Platform{}, name)
|
oldContainer, err := client.ContainerCreate(ctx, config, hostConf, &oldNetworkConf, &v1.Platform{}, name)
|
||||||
@@ -1262,12 +1271,12 @@ func loadContainerPortForInfo(itemPorts []types.Port) []dto.PortHelper {
|
|||||||
var exposedPorts []dto.PortHelper
|
var exposedPorts []dto.PortHelper
|
||||||
samePortMap := make(map[string]dto.PortHelper)
|
samePortMap := make(map[string]dto.PortHelper)
|
||||||
ports := transPortToStr(itemPorts)
|
ports := transPortToStr(itemPorts)
|
||||||
var itemPort dto.PortHelper
|
|
||||||
for _, item := range ports {
|
for _, item := range ports {
|
||||||
itemStr := strings.Split(item, "->")
|
itemStr := strings.Split(item, "->")
|
||||||
if len(itemStr) < 2 {
|
if len(itemStr) < 2 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
var itemPort dto.PortHelper
|
||||||
lastIndex := strings.LastIndex(itemStr[0], ":")
|
lastIndex := strings.LastIndex(itemStr[0], ":")
|
||||||
if lastIndex == -1 {
|
if lastIndex == -1 {
|
||||||
itemPort.HostPort = itemStr[0]
|
itemPort.HostPort = itemStr[0]
|
||||||
|
|||||||
@@ -114,8 +114,17 @@ func (u *CronjobService) CleanRecord(req dto.CronjobClean) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if !req.CleanRemoteData {
|
||||||
|
for key := range accountMap {
|
||||||
|
if key != constant.Local {
|
||||||
|
delete(accountMap, key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
cronjob.RetainCopies = 0
|
cronjob.RetainCopies = 0
|
||||||
u.removeExpiredBackup(cronjob, accountMap, model.BackupRecord{})
|
if len(accountMap) != 0 {
|
||||||
|
u.removeExpiredBackup(cronjob, accountMap, model.BackupRecord{})
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
u.removeExpiredLog(cronjob)
|
u.removeExpiredLog(cronjob)
|
||||||
}
|
}
|
||||||
@@ -249,7 +258,7 @@ func (u *CronjobService) Delete(req dto.CronjobBatchDelete) error {
|
|||||||
global.Cron.Remove(cron.EntryID(idItem))
|
global.Cron.Remove(cron.EntryID(idItem))
|
||||||
}
|
}
|
||||||
global.LOG.Infof("stop cronjob entryID: %s", cronjob.EntryIDs)
|
global.LOG.Infof("stop cronjob entryID: %s", cronjob.EntryIDs)
|
||||||
if err := u.CleanRecord(dto.CronjobClean{CronjobID: id, CleanData: req.CleanData, IsDelete: true}); err != nil {
|
if err := u.CleanRecord(dto.CronjobClean{CronjobID: id, CleanData: req.CleanData, CleanRemoteData: req.CleanRemoteData, IsDelete: true}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := cronjobRepo.Delete(commonRepo.WithByID(id)); err != nil {
|
if err := cronjobRepo.Delete(commonRepo.WithByID(id)); err != nil {
|
||||||
|
|||||||
@@ -322,7 +322,8 @@ func (u *CronjobService) uploadCronjobBackFile(cronjob model.Cronjob, accountMap
|
|||||||
if len(account) != 0 {
|
if len(account) != 0 {
|
||||||
global.LOG.Debugf("start upload file to %s, dir: %s", account, path.Join(accountMap[account].backupPath, cloudSrc))
|
global.LOG.Debugf("start upload file to %s, dir: %s", account, path.Join(accountMap[account].backupPath, cloudSrc))
|
||||||
if _, err := accountMap[account].client.Upload(file, path.Join(accountMap[account].backupPath, cloudSrc)); err != nil {
|
if _, err := accountMap[account].client.Upload(file, path.Join(accountMap[account].backupPath, cloudSrc)); err != nil {
|
||||||
return "", err
|
global.LOG.Errorf("upload file to %s failed, err: %v", account, err)
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
global.LOG.Debugf("upload successful!")
|
global.LOG.Debugf("upload successful!")
|
||||||
}
|
}
|
||||||
@@ -349,12 +350,18 @@ func (u *CronjobService) removeExpiredBackup(cronjob model.Cronjob, accountMap m
|
|||||||
if cronjob.Type == "snapshot" {
|
if cronjob.Type == "snapshot" {
|
||||||
for _, account := range accounts {
|
for _, account := range accounts {
|
||||||
if len(account) != 0 {
|
if len(account) != 0 {
|
||||||
|
if _, ok := accountMap[account]; !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
_, _ = accountMap[account].client.Delete(path.Join(accountMap[account].backupPath, "system_snapshot", records[i].FileName))
|
_, _ = accountMap[account].client.Delete(path.Join(accountMap[account].backupPath, "system_snapshot", records[i].FileName))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ = snapshotRepo.Delete(commonRepo.WithByName(strings.TrimSuffix(records[i].FileName, ".tar.gz")))
|
_ = snapshotRepo.Delete(commonRepo.WithByName(strings.TrimSuffix(records[i].FileName, ".tar.gz")))
|
||||||
} else {
|
} else {
|
||||||
for _, account := range accounts {
|
for _, account := range accounts {
|
||||||
|
if _, ok := accountMap[account]; !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
if len(account) != 0 {
|
if len(account) != 0 {
|
||||||
_, _ = accountMap[account].client.Delete(path.Join(accountMap[account].backupPath, records[i].FileDir, records[i].FileName))
|
_, _ = accountMap[account].client.Delete(path.Join(accountMap[account].backupPath, records[i].FileDir, records[i].FileName))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,19 +10,19 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
|
||||||
"github.com/shirou/gopsutil/v3/load"
|
|
||||||
"github.com/shirou/gopsutil/v3/mem"
|
|
||||||
"github.com/shirou/gopsutil/v3/net"
|
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||||
"github.com/1Panel-dev/1Panel/backend/global"
|
"github.com/1Panel-dev/1Panel/backend/global"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/utils/ai_tools/gpu"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/utils/ai_tools/xpu"
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/copier"
|
"github.com/1Panel-dev/1Panel/backend/utils/copier"
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/xpack"
|
|
||||||
"github.com/shirou/gopsutil/v3/cpu"
|
"github.com/shirou/gopsutil/v3/cpu"
|
||||||
"github.com/shirou/gopsutil/v3/disk"
|
"github.com/shirou/gopsutil/v3/disk"
|
||||||
"github.com/shirou/gopsutil/v3/host"
|
"github.com/shirou/gopsutil/v3/host"
|
||||||
|
"github.com/shirou/gopsutil/v3/load"
|
||||||
|
"github.com/shirou/gopsutil/v3/mem"
|
||||||
|
"github.com/shirou/gopsutil/v3/net"
|
||||||
)
|
)
|
||||||
|
|
||||||
type DashboardService struct{}
|
type DashboardService struct{}
|
||||||
@@ -341,7 +341,17 @@ func loadDiskInfo() []dto.DiskInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func loadGPUInfo() []dto.GPUInfo {
|
func loadGPUInfo() []dto.GPUInfo {
|
||||||
list := xpack.LoadGpuInfo()
|
ok, client := gpu.New()
|
||||||
|
var list []interface{}
|
||||||
|
if ok {
|
||||||
|
info, err := client.LoadGpuInfo()
|
||||||
|
if err != nil || len(info.GPUs) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
for _, item := range info.GPUs {
|
||||||
|
list = append(list, item)
|
||||||
|
}
|
||||||
|
}
|
||||||
if len(list) == 0 {
|
if len(list) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -359,7 +369,17 @@ func loadGPUInfo() []dto.GPUInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func loadXpuInfo() []dto.XPUInfo {
|
func loadXpuInfo() []dto.XPUInfo {
|
||||||
list := xpack.LoadXpuInfo()
|
var list []interface{}
|
||||||
|
ok, xpuClient := xpu.New()
|
||||||
|
if ok {
|
||||||
|
xpus, err := xpuClient.LoadDashData()
|
||||||
|
if err != nil || len(xpus) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
for _, item := range xpus {
|
||||||
|
list = append(list, item)
|
||||||
|
}
|
||||||
|
}
|
||||||
if len(list) == 0 {
|
if len(list) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,10 +50,6 @@ func (u *DBCommonService) LoadDatabaseFile(req dto.OperationWithNameAndType) (st
|
|||||||
filePath = path.Join(global.CONF.System.DataDir, fmt.Sprintf("apps/postgresql/%s/data/postgresql.conf", req.Name))
|
filePath = path.Join(global.CONF.System.DataDir, fmt.Sprintf("apps/postgresql/%s/data/postgresql.conf", req.Name))
|
||||||
case "redis-conf":
|
case "redis-conf":
|
||||||
filePath = path.Join(global.CONF.System.DataDir, fmt.Sprintf("apps/redis/%s/conf/redis.conf", req.Name))
|
filePath = path.Join(global.CONF.System.DataDir, fmt.Sprintf("apps/redis/%s/conf/redis.conf", req.Name))
|
||||||
case "mysql-slow-logs":
|
|
||||||
filePath = path.Join(global.CONF.System.DataDir, fmt.Sprintf("apps/mysql/%s/data/1Panel-slow.log", req.Name))
|
|
||||||
case "mariadb-slow-logs":
|
|
||||||
filePath = path.Join(global.CONF.System.DataDir, fmt.Sprintf("apps/mariadb/%s/db/data/1Panel-slow.log", req.Name))
|
|
||||||
}
|
}
|
||||||
if _, err := os.Stat(filePath); err != nil {
|
if _, err := os.Stat(filePath); err != nil {
|
||||||
return "", buserr.New("ErrHttpReqNotFound")
|
return "", buserr.New("ErrHttpReqNotFound")
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import (
|
|||||||
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/ntp"
|
"github.com/1Panel-dev/1Panel/backend/utils/ntp"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/utils/systemctl"
|
||||||
"github.com/shirou/gopsutil/v3/mem"
|
"github.com/shirou/gopsutil/v3/mem"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -121,7 +122,7 @@ func (u *DeviceService) Update(key, value string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
go func() {
|
go func() {
|
||||||
_, err := cmd.Exec("systemctl restart 1panel.service")
|
err := systemctl.Restart("1panel")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
global.LOG.Errorf("restart system for new time zone failed, err: %v", err)
|
global.LOG.Errorf("restart system for new time zone failed, err: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,12 +11,12 @@ import (
|
|||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/docker"
|
"github.com/1Panel-dev/1Panel/backend/utils/docker"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/utils/systemctl"
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/api/types/filters"
|
"github.com/docker/docker/api/types/filters"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||||
"github.com/1Panel-dev/1Panel/backend/global"
|
"github.com/1Panel-dev/1Panel/backend/global"
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
||||||
fileUtils "github.com/1Panel-dev/1Panel/backend/utils/files"
|
fileUtils "github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
@@ -285,7 +285,7 @@ func (u *DeviceService) Clean(req []dto.Clean) {
|
|||||||
|
|
||||||
if restart {
|
if restart {
|
||||||
go func() {
|
go func() {
|
||||||
_, err := cmd.Exec("systemctl restart 1panel.service")
|
err := systemctl.Restart("1panel")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
global.LOG.Errorf("restart system port failed, err: %v", err)
|
global.LOG.Errorf("restart system port failed, err: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -365,17 +365,18 @@ func (u *DockerService) UpdateConfByFile(req dto.DaemonJsonUpdateByFile) error {
|
|||||||
|
|
||||||
func (u *DockerService) OperateDocker(req dto.DockerOperation) error {
|
func (u *DockerService) OperateDocker(req dto.DockerOperation) error {
|
||||||
service := "docker"
|
service := "docker"
|
||||||
sudo := cmd.SudoHandleCmd()
|
h, err := systemctl.DefaultHandler(service)
|
||||||
dockerCmd, err := getDockerRestartCommand()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if req.Operation == "stop" {
|
if req.Operation == "stop" {
|
||||||
isSocketActive, _ := systemctl.IsActive("docker.socket")
|
socketHandle, err := systemctl.DefaultHandler("docker.socket")
|
||||||
if isSocketActive {
|
if err == nil {
|
||||||
std, err := cmd.Execf("%s systemctl stop docker.socket", sudo)
|
status, err := socketHandle.IsActive()
|
||||||
if err != nil {
|
if err == nil && status.IsActive {
|
||||||
global.LOG.Errorf("handle systemctl stop docker.socket failed, err: %v", std)
|
if std, err := socketHandle.ExecuteAction("stop"); err != nil {
|
||||||
|
global.LOG.Errorf("handle stop docker.socket failed, err: %v", std)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -386,13 +387,20 @@ func (u *DockerService) OperateDocker(req dto.DockerOperation) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stdout, err := cmd.Execf("%s %s %s", dockerCmd, req.Operation, service)
|
if isDockerSnapInstalled() {
|
||||||
|
command := fmt.Sprintf("snap %s docker", req.Operation)
|
||||||
|
stdout, err := cmd.Exec(command)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to restart docker: %v", stdout)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
result, err := h.ExecuteAction(req.Operation)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New(stdout)
|
return errors.New(result.Output)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func changeLogOption(daemonMap map[string]interface{}, logMaxFile, logMaxSize string) {
|
func changeLogOption(daemonMap map[string]interface{}, logMaxFile, logMaxSize string) {
|
||||||
if opts, ok := daemonMap["log-opts"]; ok {
|
if opts, ok := daemonMap["log-opts"]; ok {
|
||||||
if len(logMaxFile) != 0 || len(logMaxSize) != 0 {
|
if len(logMaxFile) != 0 || len(logMaxSize) != 0 {
|
||||||
@@ -451,31 +459,27 @@ func validateDockerConfig() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if err != nil || (stdout != "" && strings.TrimSpace(stdout) != "configuration OK") {
|
if err != nil || (stdout != "" && strings.TrimSpace(stdout) != "configuration OK") {
|
||||||
return fmt.Errorf("Docker configuration validation failed, err: %v", stdout)
|
return fmt.Errorf("docker configuration validation failed, err: %v", stdout)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getDockerRestartCommand() (string, error) {
|
func isDockerSnapInstalled() bool {
|
||||||
stdout, err := cmd.Exec("which docker")
|
stdout, err := cmd.Exec("which docker")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("failed to find docker: %v", err)
|
return false
|
||||||
}
|
}
|
||||||
dockerPath := stdout
|
stdout = strings.TrimSpace(stdout)
|
||||||
if strings.Contains(dockerPath, "snap") {
|
return strings.Contains(stdout, "snap")
|
||||||
return "snap", nil
|
|
||||||
}
|
|
||||||
return "systemctl", nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func restartDocker() error {
|
func restartDocker() error {
|
||||||
restartCmd, err := getDockerRestartCommand()
|
if isDockerSnapInstalled() {
|
||||||
if err != nil {
|
stdout, err := cmd.Exec("snap restart docker")
|
||||||
return err
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to restart docker: %v", stdout)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
stdout, err := cmd.Execf("%s restart docker", restartCmd)
|
return systemctl.Restart("docker")
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to restart Docker: %s", stdout)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ var (
|
|||||||
appInstallRepo = repo.NewIAppInstallRepo()
|
appInstallRepo = repo.NewIAppInstallRepo()
|
||||||
appInstallResourceRepo = repo.NewIAppInstallResourceRpo()
|
appInstallResourceRepo = repo.NewIAppInstallResourceRpo()
|
||||||
|
|
||||||
|
aiRepo = repo.NewIAiRepo()
|
||||||
|
|
||||||
mysqlRepo = repo.NewIMysqlRepo()
|
mysqlRepo = repo.NewIMysqlRepo()
|
||||||
postgresqlRepo = repo.NewIPostgresqlRepo()
|
postgresqlRepo = repo.NewIPostgresqlRepo()
|
||||||
databaseRepo = repo.NewIDatabaseRepo()
|
databaseRepo = repo.NewIDatabaseRepo()
|
||||||
@@ -44,4 +46,6 @@ var (
|
|||||||
phpExtensionsRepo = repo.NewIPHPExtensionsRepo()
|
phpExtensionsRepo = repo.NewIPHPExtensionsRepo()
|
||||||
|
|
||||||
favoriteRepo = repo.NewIFavoriteRepo()
|
favoriteRepo = repo.NewIFavoriteRepo()
|
||||||
|
|
||||||
|
mcpServerRepo = repo.NewIMcpServerRepo()
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ type IFileService interface {
|
|||||||
ChangeMode(op request.FileCreate) error
|
ChangeMode(op request.FileCreate) error
|
||||||
BatchChangeModeAndOwner(op request.FileRoleReq) error
|
BatchChangeModeAndOwner(op request.FileRoleReq) error
|
||||||
ReadLogByLine(req request.FileReadByLineReq) (*response.FileLineContent, error)
|
ReadLogByLine(req request.FileReadByLineReq) (*response.FileLineContent, error)
|
||||||
|
BatchCheckFiles(req request.FilePathsCheck) []response.ExistFileInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
var filteredPaths = []string{
|
var filteredPaths = []string{
|
||||||
@@ -365,10 +366,18 @@ func (f *FileService) MvFile(m request.FileMove) error {
|
|||||||
return buserr.New(constant.ErrMovePathFailed)
|
return buserr.New(constant.ErrMovePathFailed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
var errs []error
|
||||||
if m.Type == "cut" {
|
if m.Type == "cut" {
|
||||||
|
if len(m.CoverPaths) > 0 {
|
||||||
|
for _, src := range m.CoverPaths {
|
||||||
|
if err := fo.CopyAndReName(src, m.NewPath, "", true); err != nil {
|
||||||
|
errs = append(errs, err)
|
||||||
|
global.LOG.Errorf("cut copy file [%s] to [%s] failed, err: %s", src, m.NewPath, err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return fo.Cut(m.OldPaths, m.NewPath, m.Name, m.Cover)
|
return fo.Cut(m.OldPaths, m.NewPath, m.Name, m.Cover)
|
||||||
}
|
}
|
||||||
var errs []error
|
|
||||||
if m.Type == "copy" {
|
if m.Type == "copy" {
|
||||||
for _, src := range m.OldPaths {
|
for _, src := range m.OldPaths {
|
||||||
if err := fo.CopyAndReName(src, m.NewPath, m.Name, m.Cover); err != nil {
|
if err := fo.CopyAndReName(src, m.NewPath, m.Name, m.Cover); err != nil {
|
||||||
@@ -478,6 +487,12 @@ func (f *FileService) ReadLogByLine(req request.FileReadByLineReq) (*response.Fi
|
|||||||
}
|
}
|
||||||
case "image-pull", "image-push", "image-build", "compose-create":
|
case "image-pull", "image-push", "image-build", "compose-create":
|
||||||
logFilePath = path.Join(global.CONF.System.TmpDir, fmt.Sprintf("docker_logs/%s", req.Name))
|
logFilePath = path.Join(global.CONF.System.TmpDir, fmt.Sprintf("docker_logs/%s", req.Name))
|
||||||
|
case "ollama-model":
|
||||||
|
logFilePath = path.Join(global.CONF.System.DataDir, "log", "AITools", req.Name)
|
||||||
|
case "mysql-slow-logs":
|
||||||
|
logFilePath = path.Join(global.CONF.System.DataDir, fmt.Sprintf("apps/mysql/%s/data/1Panel-slow.log", req.Name))
|
||||||
|
case "mariadb-slow-logs":
|
||||||
|
logFilePath = path.Join(global.CONF.System.DataDir, fmt.Sprintf("apps/mariadb/%s/db/data/1Panel-slow.log", req.Name))
|
||||||
}
|
}
|
||||||
|
|
||||||
lines, isEndOfFile, total, err := files.ReadFileByLine(logFilePath, req.Page, req.PageSize, req.Latest)
|
lines, isEndOfFile, total, err := files.ReadFileByLine(logFilePath, req.Page, req.PageSize, req.Latest)
|
||||||
@@ -501,3 +516,19 @@ func (f *FileService) ReadLogByLine(req request.FileReadByLineReq) (*response.Fi
|
|||||||
}
|
}
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *FileService) BatchCheckFiles(req request.FilePathsCheck) []response.ExistFileInfo {
|
||||||
|
fileList := make([]response.ExistFileInfo, 0, len(req.Paths))
|
||||||
|
for _, filePath := range req.Paths {
|
||||||
|
if info, err := os.Stat(filePath); err == nil {
|
||||||
|
fileList = append(fileList, response.ExistFileInfo{
|
||||||
|
Size: float64(info.Size()),
|
||||||
|
Name: info.Name(),
|
||||||
|
Path: filePath,
|
||||||
|
ModTime: info.ModTime(),
|
||||||
|
IsDir: info.IsDir(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fileList
|
||||||
|
}
|
||||||
|
|||||||
@@ -381,6 +381,10 @@ func (u *FirewallService) OperateForwardRule(req dto.ForwardRuleOperate) error {
|
|||||||
TargetIP: r.TargetIP,
|
TargetIP: r.TargetIP,
|
||||||
TargetPort: r.TargetPort,
|
TargetPort: r.TargetPort,
|
||||||
}, r.Operation); err != nil {
|
}, r.Operation); err != nil {
|
||||||
|
if req.ForceDelete {
|
||||||
|
global.LOG.Error(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-11
@@ -103,23 +103,28 @@ func (f *FtpService) Sync() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
currentData := make(map[string]model.Ftp)
|
||||||
|
for _, item := range listsInDB {
|
||||||
|
currentData[item.User] = item
|
||||||
|
}
|
||||||
|
|
||||||
sameData := make(map[string]struct{})
|
sameData := make(map[string]struct{})
|
||||||
for _, item := range lists {
|
for _, item := range lists {
|
||||||
for _, itemInDB := range listsInDB {
|
if itemInDB, ok := currentData[item.User]; ok {
|
||||||
if item.User == itemInDB.User {
|
sameData[item.User] = struct{}{}
|
||||||
sameData[item.User] = struct{}{}
|
if item.Path != itemInDB.Path || item.Status != itemInDB.Status {
|
||||||
if item.Path != itemInDB.Path || item.Status != itemInDB.Status {
|
if err := ftpRepo.Update(itemInDB.ID, map[string]interface{}{"path": item.Path, "status": item.Status}); err != nil {
|
||||||
_ = ftpRepo.Update(itemInDB.ID, map[string]interface{}{"path": item.Path, "status": item.Status})
|
return err
|
||||||
}
|
}
|
||||||
break
|
}
|
||||||
|
} else {
|
||||||
|
if err := ftpRepo.Create(&model.Ftp{User: item.User, Path: item.Path, Status: item.Status}); err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, item := range lists {
|
|
||||||
if _, ok := sameData[item.User]; !ok {
|
|
||||||
_ = ftpRepo.Create(&model.Ftp{User: item.User, Path: item.Path, Status: item.Status})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, item := range listsInDB {
|
for _, item := range listsInDB {
|
||||||
if _, ok := sameData[item.User]; !ok {
|
if _, ok := sameData[item.User]; !ok {
|
||||||
_ = ftpRepo.Update(item.ID, map[string]interface{}{"status": "deleted"})
|
_ = ftpRepo.Update(item.ID, map[string]interface{}{"status": "deleted"})
|
||||||
|
|||||||
@@ -3,6 +3,12 @@ package service
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os/exec"
|
||||||
|
"os/user"
|
||||||
|
"path"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
|
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/dto/response"
|
"github.com/1Panel-dev/1Panel/backend/app/dto/response"
|
||||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||||
@@ -14,11 +20,6 @@ import (
|
|||||||
"github.com/1Panel-dev/1Panel/backend/utils/systemctl"
|
"github.com/1Panel-dev/1Panel/backend/utils/systemctl"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"gopkg.in/ini.v1"
|
"gopkg.in/ini.v1"
|
||||||
"os/exec"
|
|
||||||
"os/user"
|
|
||||||
"path"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type HostToolService struct{}
|
type HostToolService struct{}
|
||||||
@@ -39,93 +40,108 @@ func NewIHostToolService() IHostToolService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *HostToolService) GetToolStatus(req request.HostToolReq) (*response.HostToolRes, error) {
|
func (h *HostToolService) GetToolStatus(req request.HostToolReq) (*response.HostToolRes, error) {
|
||||||
res := &response.HostToolRes{}
|
res := &response.HostToolRes{Type: req.Type}
|
||||||
res.Type = req.Type
|
|
||||||
switch req.Type {
|
switch req.Type {
|
||||||
case constant.Supervisord:
|
case constant.Supervisord:
|
||||||
supervisorConfig := &response.Supervisor{}
|
return h.getSupervisorStatus(res)
|
||||||
if !cmd.Which(constant.Supervisord) {
|
|
||||||
supervisorConfig.IsExist = false
|
|
||||||
res.Config = supervisorConfig
|
|
||||||
return res, nil
|
|
||||||
}
|
|
||||||
supervisorConfig.IsExist = true
|
|
||||||
serviceExist, _ := systemctl.IsExist(constant.Supervisord)
|
|
||||||
if !serviceExist {
|
|
||||||
serviceExist, _ = systemctl.IsExist(constant.Supervisor)
|
|
||||||
if !serviceExist {
|
|
||||||
supervisorConfig.IsExist = false
|
|
||||||
res.Config = supervisorConfig
|
|
||||||
return res, nil
|
|
||||||
} else {
|
|
||||||
supervisorConfig.ServiceName = constant.Supervisor
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
supervisorConfig.ServiceName = constant.Supervisord
|
|
||||||
}
|
|
||||||
|
|
||||||
serviceNameSet, _ := settingRepo.Get(settingRepo.WithByKey(constant.SupervisorServiceName))
|
|
||||||
if serviceNameSet.ID != 0 || serviceNameSet.Value != "" {
|
|
||||||
supervisorConfig.ServiceName = serviceNameSet.Value
|
|
||||||
}
|
|
||||||
|
|
||||||
versionRes, _ := cmd.Exec("supervisord -v")
|
|
||||||
supervisorConfig.Version = strings.TrimSuffix(versionRes, "\n")
|
|
||||||
_, ctlRrr := exec.LookPath("supervisorctl")
|
|
||||||
supervisorConfig.CtlExist = ctlRrr == nil
|
|
||||||
|
|
||||||
active, _ := systemctl.IsActive(supervisorConfig.ServiceName)
|
|
||||||
if active {
|
|
||||||
supervisorConfig.Status = "running"
|
|
||||||
} else {
|
|
||||||
supervisorConfig.Status = "stopped"
|
|
||||||
}
|
|
||||||
|
|
||||||
pathSet, _ := settingRepo.Get(settingRepo.WithByKey(constant.SupervisorConfigPath))
|
|
||||||
if pathSet.ID != 0 || pathSet.Value != "" {
|
|
||||||
supervisorConfig.ConfigPath = pathSet.Value
|
|
||||||
res.Config = supervisorConfig
|
|
||||||
return res, nil
|
|
||||||
} else {
|
|
||||||
supervisorConfig.Init = true
|
|
||||||
}
|
|
||||||
|
|
||||||
servicePath := "/usr/lib/systemd/system/supervisor.service"
|
|
||||||
fileOp := files.NewFileOp()
|
|
||||||
if !fileOp.Stat(servicePath) {
|
|
||||||
servicePath = "/usr/lib/systemd/system/supervisord.service"
|
|
||||||
}
|
|
||||||
if fileOp.Stat(servicePath) {
|
|
||||||
startCmd, _ := ini_conf.GetIniValue(servicePath, "Service", "ExecStart")
|
|
||||||
if startCmd != "" {
|
|
||||||
args := strings.Fields(startCmd)
|
|
||||||
cIndex := -1
|
|
||||||
for i, arg := range args {
|
|
||||||
if arg == "-c" {
|
|
||||||
cIndex = i
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if cIndex != -1 && cIndex+1 < len(args) {
|
|
||||||
supervisorConfig.ConfigPath = args[cIndex+1]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if supervisorConfig.ConfigPath == "" {
|
|
||||||
configPath := "/etc/supervisord.conf"
|
|
||||||
if !fileOp.Stat(configPath) {
|
|
||||||
configPath = "/etc/supervisor/supervisord.conf"
|
|
||||||
if fileOp.Stat(configPath) {
|
|
||||||
supervisorConfig.ConfigPath = configPath
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
res.Config = supervisorConfig
|
|
||||||
}
|
}
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *HostToolService) getSupervisorStatus(res *response.HostToolRes) (*response.HostToolRes, error) {
|
||||||
|
supervisorConfig := &response.Supervisor{}
|
||||||
|
if !cmd.Which(constant.Supervisord) {
|
||||||
|
supervisorConfig.IsExist = false
|
||||||
|
res.Config = supervisorConfig
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
supervisorConfig.IsExist = true
|
||||||
|
|
||||||
|
serviceName, err := h.determineServiceName()
|
||||||
|
if err != nil || serviceName == "" {
|
||||||
|
supervisorConfig.IsExist = false
|
||||||
|
res.Config = supervisorConfig
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
supervisorConfig.ServiceName = serviceName
|
||||||
|
|
||||||
|
if nameSetting, _ := settingRepo.Get(settingRepo.WithByKey(constant.SupervisorServiceName)); nameSetting.Value != "" {
|
||||||
|
supervisorConfig.ServiceName = nameSetting.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
if version, err := cmd.Exec("supervisord -v"); err == nil {
|
||||||
|
supervisorConfig.Version = strings.TrimSpace(version)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, errCtl := exec.LookPath("supervisorctl")
|
||||||
|
supervisorConfig.CtlExist = errCtl == nil
|
||||||
|
|
||||||
|
if active, err := systemctl.IsActive(supervisorConfig.ServiceName); err == nil && active {
|
||||||
|
supervisorConfig.Status = "running"
|
||||||
|
} else {
|
||||||
|
supervisorConfig.Status = "stopped"
|
||||||
|
}
|
||||||
|
|
||||||
|
h.resolveConfigPath(supervisorConfig)
|
||||||
|
|
||||||
|
res.Config = supervisorConfig
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *HostToolService) determineServiceName() (string, error) {
|
||||||
|
if setting, _ := settingRepo.Get(settingRepo.WithByKey(constant.SupervisorServiceName)); setting.Value != "" {
|
||||||
|
serviceName, err := systemctl.GetServiceName(setting.Value)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("get service name error: %v", err)
|
||||||
|
}
|
||||||
|
return serviceName, nil
|
||||||
|
}
|
||||||
|
if serviceName, err := systemctl.GetServiceName(constant.Supervisord); err == nil {
|
||||||
|
return serviceName, nil
|
||||||
|
}
|
||||||
|
return systemctl.GetServiceName(constant.Supervisor)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *HostToolService) resolveConfigPath(config *response.Supervisor) {
|
||||||
|
if pathSetting, _ := settingRepo.Get(settingRepo.WithByKey(constant.SupervisorConfigPath)); pathSetting.Value != "" {
|
||||||
|
config.ConfigPath = pathSetting.Value
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
config.Init = true
|
||||||
|
|
||||||
|
if servicePath, err := systemctl.GetServicePath(config.ServiceName); err == nil {
|
||||||
|
if startCmd, _ := ini_conf.GetIniValue(servicePath, "Service", "ExecStart"); startCmd != "" {
|
||||||
|
if path := parseConfigPathFromCommand(startCmd); path != "" {
|
||||||
|
config.ConfigPath = path
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultPaths := []string{
|
||||||
|
"/etc/supervisord.conf",
|
||||||
|
"/etc/supervisor/supervisord.conf",
|
||||||
|
"/usr/local/etc/supervisord.conf",
|
||||||
|
}
|
||||||
|
for _, path := range defaultPaths {
|
||||||
|
if systemctl.FileExist(path) {
|
||||||
|
config.ConfigPath = path
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseConfigPathFromCommand(cmd string) string {
|
||||||
|
parts := strings.Fields(cmd)
|
||||||
|
for i, part := range parts {
|
||||||
|
if part == "-c" && i+1 < len(parts) {
|
||||||
|
return parts[i+1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
func (h *HostToolService) CreateToolConfig(req request.HostToolCreate) error {
|
func (h *HostToolService) CreateToolConfig(req request.HostToolCreate) error {
|
||||||
switch req.Type {
|
switch req.Type {
|
||||||
case constant.Supervisord:
|
case constant.Supervisord:
|
||||||
@@ -200,14 +216,28 @@ func (h *HostToolService) CreateToolConfig(req request.HostToolCreate) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *HostToolService) OperateTool(req request.HostToolReq) error {
|
func (h *HostToolService) OperateTool(req request.HostToolReq) error {
|
||||||
serviceName := req.Type
|
var serviceName string
|
||||||
if req.Type == constant.Supervisord {
|
var err error
|
||||||
|
switch req.Type {
|
||||||
|
case constant.Supervisord:
|
||||||
serviceNameSet, _ := settingRepo.Get(settingRepo.WithByKey(constant.SupervisorServiceName))
|
serviceNameSet, _ := settingRepo.Get(settingRepo.WithByKey(constant.SupervisorServiceName))
|
||||||
if serviceNameSet.ID != 0 || serviceNameSet.Value != "" {
|
if serviceNameSet.ID != 0 || serviceNameSet.Value != "" {
|
||||||
serviceName = serviceNameSet.Value
|
serviceName = serviceNameSet.Value
|
||||||
|
} else {
|
||||||
|
serviceName = req.Type
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
|
serviceName = req.Type
|
||||||
}
|
}
|
||||||
return systemctl.Operate(req.Operate, serviceName)
|
serviceName, err = systemctl.GetServiceName(serviceName)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, systemctl.ErrServiceNotFound) {
|
||||||
|
return fmt.Errorf("%s service unavailable. Please ensure supervisor server is installed and configured", serviceName)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = systemctl.CustomAction(req.Operate, serviceName)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HostToolService) OperateToolConfig(req request.HostToolConfig) (*response.HostToolConfig, error) {
|
func (h *HostToolService) OperateToolConfig(req request.HostToolConfig) (*response.HostToolConfig, error) {
|
||||||
|
|||||||
@@ -439,6 +439,9 @@ func (u *ImageService) ImageRemove(req dto.BatchDelete) error {
|
|||||||
}
|
}
|
||||||
return buserr.WithDetail(constant.ErrInUsed, id, nil)
|
return buserr.WithDetail(constant.ErrInUsed, id, nil)
|
||||||
}
|
}
|
||||||
|
if strings.Contains(err.Error(), "image has dependent") {
|
||||||
|
return buserr.New(constant.ErrObjectBeDependent)
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ type IImageRepoService interface {
|
|||||||
Login(req dto.OperateByID) error
|
Login(req dto.OperateByID) error
|
||||||
Create(req dto.ImageRepoCreate) error
|
Create(req dto.ImageRepoCreate) error
|
||||||
Update(req dto.ImageRepoUpdate) error
|
Update(req dto.ImageRepoUpdate) error
|
||||||
BatchDelete(req dto.ImageRepoDelete) error
|
Delete(req dto.OperateByID) error
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewIImageRepoService() IImageRepoService {
|
func NewIImageRepoService() IImageRepoService {
|
||||||
@@ -89,31 +89,7 @@ func (u *ImageRepoService) Create(req dto.ImageRepoCreate) error {
|
|||||||
if err := u.handleRegistries(req.DownloadUrl, "", "create"); err != nil {
|
if err := u.handleRegistries(req.DownloadUrl, "", "create"); err != nil {
|
||||||
return fmt.Errorf("create registry %s failed, err: %v", req.DownloadUrl, err)
|
return fmt.Errorf("create registry %s failed, err: %v", req.DownloadUrl, err)
|
||||||
}
|
}
|
||||||
if err := validateDockerConfig(); err != nil {
|
if err := stopBeforeUpdateRepo(); err != nil {
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := restartDocker(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
ticker := time.NewTicker(3 * time.Second)
|
|
||||||
defer ticker.Stop()
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*20)
|
|
||||||
if err := func() error {
|
|
||||||
for range ticker.C {
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
cancel()
|
|
||||||
return errors.New("the docker service cannot be restarted")
|
|
||||||
default:
|
|
||||||
stdout, err := cmd.Exec("systemctl is-active docker")
|
|
||||||
if string(stdout) == "active\n" && err == nil {
|
|
||||||
global.LOG.Info("docker restart with new conf successful!")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}(); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -131,15 +107,32 @@ func (u *ImageRepoService) Create(req dto.ImageRepoCreate) error {
|
|||||||
return imageRepoRepo.Create(&imageRepo)
|
return imageRepoRepo.Create(&imageRepo)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *ImageRepoService) BatchDelete(req dto.ImageRepoDelete) error {
|
func (u *ImageRepoService) Delete(req dto.OperateByID) error {
|
||||||
for _, id := range req.Ids {
|
if req.ID == 1 {
|
||||||
if id == 1 {
|
return errors.New("The default value cannot be edit !")
|
||||||
return errors.New("The default value cannot be edit !")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if err := imageRepoRepo.Delete(commonRepo.WithIdsIn(req.Ids)); err != nil {
|
itemRepo, _ := imageRepoRepo.Get(commonRepo.WithByID(req.ID))
|
||||||
|
if itemRepo.ID == 0 {
|
||||||
|
return buserr.New("ErrRecordNotFound")
|
||||||
|
}
|
||||||
|
if itemRepo.Auth {
|
||||||
|
_, _ = cmd.Execf("docker logout -i %s", itemRepo.DownloadUrl)
|
||||||
|
}
|
||||||
|
if itemRepo.Protocol == "https" {
|
||||||
|
return imageRepoRepo.Delete(commonRepo.WithByID(req.ID))
|
||||||
|
}
|
||||||
|
if err := u.handleRegistries("", itemRepo.DownloadUrl, "delete"); err != nil {
|
||||||
|
return fmt.Errorf("delete registry %s failed, err: %v", itemRepo.DownloadUrl, err)
|
||||||
|
}
|
||||||
|
if err := validateDockerConfig(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if err := imageRepoRepo.Delete(commonRepo.WithByID(req.ID)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
_ = restartDocker()
|
||||||
|
}()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,37 +147,39 @@ func (u *ImageRepoService) Update(req dto.ImageRepoUpdate) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
needRestart := false
|
||||||
if repo.Protocol == "http" && req.Protocol == "https" {
|
if repo.Protocol == "http" && req.Protocol == "https" {
|
||||||
if err := u.handleRegistries("", repo.DownloadUrl, "delete"); err != nil {
|
if err := u.handleRegistries("", repo.DownloadUrl, "delete"); err != nil {
|
||||||
return fmt.Errorf("delete registry %s failed, err: %v", repo.DownloadUrl, err)
|
return fmt.Errorf("delete registry %s failed, err: %v", repo.DownloadUrl, err)
|
||||||
}
|
}
|
||||||
|
needRestart = true
|
||||||
}
|
}
|
||||||
if repo.Protocol == "http" && req.Protocol == "http" {
|
if repo.Protocol == "http" && req.Protocol == "http" {
|
||||||
if err := u.handleRegistries(req.DownloadUrl, repo.DownloadUrl, "update"); err != nil {
|
if repo.DownloadUrl != req.DownloadUrl {
|
||||||
return fmt.Errorf("update registry %s => %s failed, err: %v", repo.DownloadUrl, req.DownloadUrl, err)
|
if err := u.handleRegistries(req.DownloadUrl, repo.DownloadUrl, "update"); err != nil {
|
||||||
|
return fmt.Errorf("update registry %s => %s failed, err: %v", repo.DownloadUrl, req.DownloadUrl, err)
|
||||||
|
}
|
||||||
|
needRestart = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if repo.Protocol == "https" && req.Protocol == "http" {
|
if repo.Protocol == "https" && req.Protocol == "http" {
|
||||||
if err := u.handleRegistries(req.DownloadUrl, "", "create"); err != nil {
|
if err := u.handleRegistries(req.DownloadUrl, "", "create"); err != nil {
|
||||||
return fmt.Errorf("create registry %s failed, err: %v", req.DownloadUrl, err)
|
return fmt.Errorf("create registry %s failed, err: %v", req.DownloadUrl, err)
|
||||||
}
|
}
|
||||||
|
needRestart = true
|
||||||
}
|
}
|
||||||
if repo.Auth != req.Auth || repo.DownloadUrl != req.DownloadUrl {
|
if needRestart {
|
||||||
if repo.Auth {
|
if err := stopBeforeUpdateRepo(); err != nil {
|
||||||
_, _ = cmd.ExecWithCheck("docker", "logout", repo.DownloadUrl)
|
return err
|
||||||
}
|
|
||||||
if req.Auth {
|
|
||||||
if err := u.CheckConn(req.DownloadUrl, req.Username, req.Password); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if repo.Auth {
|
||||||
if err := validateDockerConfig(); err != nil {
|
_, _ = cmd.Execf("docker logout -i %s", repo.DownloadUrl)
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
if err := restartDocker(); err != nil {
|
if req.Auth {
|
||||||
return err
|
if err := u.CheckConn(req.DownloadUrl, req.Username, req.Password); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
upMap := make(map[string]interface{})
|
upMap := make(map[string]interface{})
|
||||||
@@ -256,3 +251,34 @@ func (u *ImageRepoService) handleRegistries(newHost, delHost, handle string) err
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func stopBeforeUpdateRepo() error {
|
||||||
|
if err := validateDockerConfig(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := restartDocker(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ticker := time.NewTicker(3 * time.Second)
|
||||||
|
defer ticker.Stop()
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
|
||||||
|
if err := func() error {
|
||||||
|
for range ticker.C {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
cancel()
|
||||||
|
return errors.New("the docker service cannot be restarted")
|
||||||
|
default:
|
||||||
|
stdout, err := cmd.Exec("systemctl is-active docker")
|
||||||
|
if string(stdout) == "active\n" && err == nil {
|
||||||
|
global.LOG.Info("docker restart with new conf successful!")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,6 +2,9 @@ package service
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/utils/geo"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@@ -26,7 +29,7 @@ const logs = "https://resource.fit2cloud.com/installation-log.sh"
|
|||||||
type ILogService interface {
|
type ILogService interface {
|
||||||
ListSystemLogFile() ([]string, error)
|
ListSystemLogFile() ([]string, error)
|
||||||
CreateLoginLog(operation model.LoginLog) error
|
CreateLoginLog(operation model.LoginLog) error
|
||||||
PageLoginLog(search dto.SearchLgLogWithPage) (int64, interface{}, error)
|
PageLoginLog(c *gin.Context, search dto.SearchLgLogWithPage) (int64, interface{}, error)
|
||||||
|
|
||||||
CreateOperationLog(operation model.OperationLog) error
|
CreateOperationLog(operation model.OperationLog) error
|
||||||
PageOperationLog(search dto.SearchOpLogWithPage) (int64, interface{}, error)
|
PageOperationLog(search dto.SearchOpLogWithPage) (int64, interface{}, error)
|
||||||
@@ -77,7 +80,7 @@ func (u *LogService) ListSystemLogFile() ([]string, error) {
|
|||||||
return files, nil
|
return files, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *LogService) PageLoginLog(req dto.SearchLgLogWithPage) (int64, interface{}, error) {
|
func (u *LogService) PageLoginLog(c *gin.Context, req dto.SearchLgLogWithPage) (int64, interface{}, error) {
|
||||||
total, ops, err := logRepo.PageLoginLog(
|
total, ops, err := logRepo.PageLoginLog(
|
||||||
req.Page,
|
req.Page,
|
||||||
req.PageSize,
|
req.PageSize,
|
||||||
@@ -91,6 +94,7 @@ func (u *LogService) PageLoginLog(req dto.SearchLgLogWithPage) (int64, interface
|
|||||||
if err := copier.Copy(&item, &op); err != nil {
|
if err := copier.Copy(&item, &op); err != nil {
|
||||||
return 0, nil, errors.WithMessage(constant.ErrStructTransform, err.Error())
|
return 0, nil, errors.WithMessage(constant.ErrStructTransform, err.Error())
|
||||||
}
|
}
|
||||||
|
item.Address, _ = geo.GetIPLocation(item.IP, common.GetLang(c))
|
||||||
dtoOps = append(dtoOps, item)
|
dtoOps = append(dtoOps, item)
|
||||||
}
|
}
|
||||||
return total, dtoOps, err
|
return total, dtoOps, err
|
||||||
|
|||||||
@@ -0,0 +1,643 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/app/dto/response"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/global"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/utils/compose"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/utils/docker"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/utils/nginx"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/utils/nginx/components"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/utils/nginx/parser"
|
||||||
|
"github.com/1Panel-dev/1Panel/cmd/server/mcp"
|
||||||
|
"github.com/1Panel-dev/1Panel/cmd/server/nginx_conf"
|
||||||
|
"github.com/subosito/gotenv"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
|
"path"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type McpServerService struct{}
|
||||||
|
|
||||||
|
type IMcpServerService interface {
|
||||||
|
Page(req request.McpServerSearch) response.McpServersRes
|
||||||
|
Create(create request.McpServerCreate) error
|
||||||
|
Update(req request.McpServerUpdate) error
|
||||||
|
Delete(id uint) error
|
||||||
|
Operate(req request.McpServerOperate) error
|
||||||
|
GetBindDomain() (response.McpBindDomainRes, error)
|
||||||
|
BindDomain(req request.McpBindDomain) error
|
||||||
|
UpdateBindDomain(req request.McpBindDomainUpdate) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewIMcpServerService() IMcpServerService {
|
||||||
|
return &McpServerService{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m McpServerService) Page(req request.McpServerSearch) response.McpServersRes {
|
||||||
|
var (
|
||||||
|
res response.McpServersRes
|
||||||
|
items []response.McpServerDTO
|
||||||
|
)
|
||||||
|
|
||||||
|
total, data, _ := mcpServerRepo.Page(req.PageInfo.Page, req.PageInfo.PageSize)
|
||||||
|
for _, item := range data {
|
||||||
|
_ = syncMcpServerContainerStatus(&item)
|
||||||
|
serverDTO := response.McpServerDTO{
|
||||||
|
McpServer: item,
|
||||||
|
Environments: make([]request.Environment, 0),
|
||||||
|
Volumes: make([]request.Volume, 0),
|
||||||
|
}
|
||||||
|
project, _ := docker.GetComposeProject(item.Name, path.Join(constant.McpDir, item.Name), []byte(item.DockerCompose), []byte(item.Env), true)
|
||||||
|
for _, service := range project.Services {
|
||||||
|
if service.Environment != nil {
|
||||||
|
for key, value := range service.Environment {
|
||||||
|
serverDTO.Environments = append(serverDTO.Environments, request.Environment{
|
||||||
|
Key: key,
|
||||||
|
Value: *value,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if service.Volumes != nil {
|
||||||
|
for _, volume := range service.Volumes {
|
||||||
|
serverDTO.Volumes = append(serverDTO.Volumes, request.Volume{
|
||||||
|
Source: volume.Source,
|
||||||
|
Target: volume.Target,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
items = append(items, serverDTO)
|
||||||
|
}
|
||||||
|
res.Total = total
|
||||||
|
res.Items = items
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m McpServerService) Update(req request.McpServerUpdate) error {
|
||||||
|
mcpServer, err := mcpServerRepo.GetFirst(commonRepo.WithByID(req.ID))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if mcpServer.Port != req.Port {
|
||||||
|
if err := checkPortExist(req.Port); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if mcpServer.ContainerName != req.ContainerName {
|
||||||
|
if err := checkContainerName(req.ContainerName); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mcpServer.Name = req.Name
|
||||||
|
mcpServer.ContainerName = req.ContainerName
|
||||||
|
mcpServer.Port = req.Port
|
||||||
|
mcpServer.Command = req.Command
|
||||||
|
mcpServer.BaseURL = req.BaseURL
|
||||||
|
mcpServer.SsePath = req.SsePath
|
||||||
|
mcpServer.HostIP = req.HostIP
|
||||||
|
if err := handleCreateParams(mcpServer, req.Environments, req.Volumes); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
env := handleEnv(mcpServer)
|
||||||
|
mcpDir := path.Join(constant.McpDir, mcpServer.Name)
|
||||||
|
envPath := path.Join(mcpDir, ".env")
|
||||||
|
if err := gotenv.Write(env, envPath); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
dockerComposePath := path.Join(mcpDir, "docker-compose.yml")
|
||||||
|
if err := files.NewFileOp().SaveFile(dockerComposePath, mcpServer.DockerCompose, 0644); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
mcpServer.Status = constant.RuntimeStarting
|
||||||
|
if err := mcpServerRepo.Save(mcpServer); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
go startMcp(mcpServer)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m McpServerService) Create(create request.McpServerCreate) error {
|
||||||
|
servers, _ := mcpServerRepo.List()
|
||||||
|
for _, server := range servers {
|
||||||
|
if server.Port == create.Port {
|
||||||
|
return buserr.New("ErrPortInUsed")
|
||||||
|
}
|
||||||
|
if server.ContainerName == create.ContainerName {
|
||||||
|
return buserr.New("ErrContainerName")
|
||||||
|
}
|
||||||
|
if server.Name == create.Name {
|
||||||
|
return buserr.New(constant.ErrNameIsExist)
|
||||||
|
}
|
||||||
|
if server.SsePath == create.SsePath {
|
||||||
|
return buserr.New("ErrSsePath")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := checkPortExist(create.Port); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := checkContainerName(create.ContainerName); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
mcpDir := path.Join(constant.McpDir, create.Name)
|
||||||
|
mcpServer := &model.McpServer{
|
||||||
|
Name: create.Name,
|
||||||
|
ContainerName: create.ContainerName,
|
||||||
|
Port: create.Port,
|
||||||
|
Command: create.Command,
|
||||||
|
Status: constant.RuntimeStarting,
|
||||||
|
BaseURL: create.BaseURL,
|
||||||
|
SsePath: create.SsePath,
|
||||||
|
Dir: mcpDir,
|
||||||
|
HostIP: create.HostIP,
|
||||||
|
}
|
||||||
|
if err := handleCreateParams(mcpServer, create.Environments, create.Volumes); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
env := handleEnv(mcpServer)
|
||||||
|
filesOP := files.NewFileOp()
|
||||||
|
if !filesOP.Stat(mcpDir) {
|
||||||
|
_ = filesOP.CreateDir(mcpDir, 0644)
|
||||||
|
}
|
||||||
|
envPath := path.Join(mcpDir, ".env")
|
||||||
|
if err := gotenv.Write(env, envPath); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
dockerComposePath := path.Join(mcpDir, "docker-compose.yml")
|
||||||
|
if err := filesOP.SaveFile(dockerComposePath, mcpServer.DockerCompose, 0644); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := mcpServerRepo.Create(mcpServer); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
addProxy(mcpServer)
|
||||||
|
go startMcp(mcpServer)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m McpServerService) Delete(id uint) error {
|
||||||
|
mcpServer, err := mcpServerRepo.GetFirst(commonRepo.WithByID(id))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
composePath := path.Join(constant.McpDir, mcpServer.Name, "docker-compose.yml")
|
||||||
|
_, _ = compose.Down(composePath)
|
||||||
|
_ = files.NewFileOp().DeleteDir(path.Join(constant.McpDir, mcpServer.Name))
|
||||||
|
|
||||||
|
websiteID := GetWebsiteID()
|
||||||
|
if websiteID > 0 {
|
||||||
|
websiteService := NewIWebsiteService()
|
||||||
|
delProxyReq := request.WebsiteProxyDel{
|
||||||
|
ID: websiteID,
|
||||||
|
Name: mcpServer.Name,
|
||||||
|
}
|
||||||
|
_ = websiteService.DeleteProxy(delProxyReq)
|
||||||
|
}
|
||||||
|
return mcpServerRepo.DeleteBy(commonRepo.WithByID(id))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m McpServerService) Operate(req request.McpServerOperate) error {
|
||||||
|
mcpServer, err := mcpServerRepo.GetFirst(commonRepo.WithByID(req.ID))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
composePath := path.Join(mcpServer.Dir, "docker-compose.yml")
|
||||||
|
var out string
|
||||||
|
switch req.Operate {
|
||||||
|
case "start":
|
||||||
|
out, err = compose.Up(composePath)
|
||||||
|
mcpServer.Status = constant.RuntimeRunning
|
||||||
|
case "stop":
|
||||||
|
out, err = compose.Down(composePath)
|
||||||
|
mcpServer.Status = constant.RuntimeStopped
|
||||||
|
case "restart":
|
||||||
|
out, err = compose.Restart(composePath)
|
||||||
|
mcpServer.Status = constant.RuntimeRunning
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
mcpServer.Status = constant.RuntimeError
|
||||||
|
mcpServer.Message = out
|
||||||
|
}
|
||||||
|
return mcpServerRepo.Save(mcpServer)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m McpServerService) GetBindDomain() (response.McpBindDomainRes, error) {
|
||||||
|
var res response.McpBindDomainRes
|
||||||
|
websiteID := GetWebsiteID()
|
||||||
|
if websiteID == 0 {
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
website, err := websiteRepo.GetFirst(commonRepo.WithByID(websiteID))
|
||||||
|
if err != nil {
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
res.WebsiteID = website.ID
|
||||||
|
res.Domain = website.PrimaryDomain
|
||||||
|
if website.WebsiteSSLID > 0 {
|
||||||
|
res.SSLID = website.WebsiteSSLID
|
||||||
|
ssl, _ := websiteSSLRepo.GetFirst(commonRepo.WithByID(website.WebsiteSSLID))
|
||||||
|
res.AcmeAccountID = ssl.AcmeAccountID
|
||||||
|
}
|
||||||
|
res.ConnUrl = fmt.Sprintf("%s://%s", strings.ToLower(website.Protocol), website.PrimaryDomain)
|
||||||
|
res.AllowIPs = GetAllowIps(website)
|
||||||
|
return res, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m McpServerService) BindDomain(req request.McpBindDomain) error {
|
||||||
|
nginxInstall, _ := getAppInstallByKey(constant.AppOpenresty)
|
||||||
|
if nginxInstall.ID == 0 {
|
||||||
|
return buserr.New("ErrOpenrestyInstall")
|
||||||
|
}
|
||||||
|
var (
|
||||||
|
ipList []string
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
if len(req.IPList) > 0 {
|
||||||
|
ipList, err = common.HandleIPList(req.IPList)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if req.SSLID > 0 {
|
||||||
|
ssl, err := websiteSSLRepo.GetFirst(commonRepo.WithByID(req.SSLID))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if ssl.Pem == "" {
|
||||||
|
return buserr.New("ErrSSL")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
group, _ := groupRepo.Get(groupRepo.WithByWebsiteDefault())
|
||||||
|
createWebsiteReq := request.WebsiteCreate{
|
||||||
|
PrimaryDomain: req.Domain,
|
||||||
|
Alias: strings.ToLower(req.Domain),
|
||||||
|
Type: constant.Static,
|
||||||
|
WebsiteGroupID: group.ID,
|
||||||
|
}
|
||||||
|
websiteService := NewIWebsiteService()
|
||||||
|
if err := websiteService.CreateWebsite(createWebsiteReq); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
website, err := websiteRepo.GetFirst(websiteRepo.WithAlias(strings.ToLower(req.Domain)))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_ = settingRepo.UpdateOrCreate("MCP_WEBSITE_ID", fmt.Sprintf("%d", website.ID))
|
||||||
|
if len(ipList) > 0 {
|
||||||
|
if err = ConfigAllowIPs(ipList, website); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if req.SSLID > 0 {
|
||||||
|
sslReq := request.WebsiteHTTPSOp{
|
||||||
|
WebsiteID: website.ID,
|
||||||
|
Enable: true,
|
||||||
|
Type: "existed",
|
||||||
|
WebsiteSSLID: req.SSLID,
|
||||||
|
HttpConfig: "HTTPSOnly",
|
||||||
|
}
|
||||||
|
if _, err = websiteService.OpWebsiteHTTPS(context.Background(), sslReq); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err = addMCPProxy(website.ID); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m McpServerService) UpdateBindDomain(req request.McpBindDomainUpdate) error {
|
||||||
|
nginxInstall, _ := getAppInstallByKey(constant.AppOpenresty)
|
||||||
|
if nginxInstall.ID == 0 {
|
||||||
|
return buserr.New("ErrOpenrestyInstall")
|
||||||
|
}
|
||||||
|
var (
|
||||||
|
ipList []string
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
if len(req.IPList) > 0 {
|
||||||
|
ipList, err = common.HandleIPList(req.IPList)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if req.SSLID > 0 {
|
||||||
|
ssl, err := websiteSSLRepo.GetFirst(commonRepo.WithByID(req.SSLID))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if ssl.Pem == "" {
|
||||||
|
return buserr.New("ErrSSL")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
websiteService := NewIWebsiteService()
|
||||||
|
website, err := websiteRepo.GetFirst(commonRepo.WithByID(req.WebsiteID))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err = ConfigAllowIPs(ipList, website); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if req.SSLID > 0 {
|
||||||
|
sslReq := request.WebsiteHTTPSOp{
|
||||||
|
WebsiteID: website.ID,
|
||||||
|
Enable: true,
|
||||||
|
Type: "existed",
|
||||||
|
WebsiteSSLID: req.SSLID,
|
||||||
|
HttpConfig: "HTTPSOnly",
|
||||||
|
}
|
||||||
|
if _, err = websiteService.OpWebsiteHTTPS(context.Background(), sslReq); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if website.WebsiteSSLID > 0 && req.SSLID == 0 {
|
||||||
|
sslReq := request.WebsiteHTTPSOp{
|
||||||
|
WebsiteID: website.ID,
|
||||||
|
Enable: false,
|
||||||
|
}
|
||||||
|
if _, err = websiteService.OpWebsiteHTTPS(context.Background(), sslReq); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
go updateMcpConfig(website.ID)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateMcpConfig(websiteID uint) {
|
||||||
|
servers, _ := mcpServerRepo.List()
|
||||||
|
if len(servers) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
website, _ := websiteRepo.GetFirst(commonRepo.WithByID(websiteID))
|
||||||
|
websiteDomain := website.Domains[0]
|
||||||
|
var baseUrl string
|
||||||
|
if website.Protocol == constant.ProtocolHTTP {
|
||||||
|
baseUrl = fmt.Sprintf("http://%s", websiteDomain.Domain)
|
||||||
|
} else {
|
||||||
|
baseUrl = fmt.Sprintf("https://%s", websiteDomain.Domain)
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for _, server := range servers {
|
||||||
|
if server.BaseURL != baseUrl {
|
||||||
|
server.BaseURL = baseUrl
|
||||||
|
server.HostIP = "127.0.0.1"
|
||||||
|
_ = updateMcpServer(&server)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func addProxy(server *model.McpServer) {
|
||||||
|
websiteID := GetWebsiteID()
|
||||||
|
website, err := websiteRepo.GetFirst(commonRepo.WithByID(websiteID))
|
||||||
|
if err != nil {
|
||||||
|
global.LOG.Errorf("[mcp] add proxy failed, err: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
|
||||||
|
if err != nil {
|
||||||
|
global.LOG.Errorf("[mcp] add proxy failed, err: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fileOp := files.NewFileOp()
|
||||||
|
includeDir := path.Join(nginxInstall.GetPath(), "www", "sites", website.Alias, "proxy")
|
||||||
|
if !fileOp.Stat(includeDir) {
|
||||||
|
if err = fileOp.CreateDir(includeDir, 0644); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
config, err := parser.NewStringParser(string(nginx_conf.SSE)).Parse()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
includePath := path.Join(includeDir, server.Name+".conf")
|
||||||
|
config.FilePath = includePath
|
||||||
|
directives := config.Directives
|
||||||
|
location, ok := directives[0].(*components.Location)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
location.UpdateDirective("proxy_pass", []string{fmt.Sprintf("http://127.0.0.1:%d%s", server.Port, server.SsePath)})
|
||||||
|
location.ChangePath("^~", server.SsePath)
|
||||||
|
if err = nginx.WriteConfig(config, nginx.IndentedStyle); err != nil {
|
||||||
|
global.LOG.Errorf("write config failed, err: %v", buserr.WithErr(constant.ErrUpdateBuWebsite, err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
nginxInclude := fmt.Sprintf("/www/sites/%s/proxy/*.conf", website.Alias)
|
||||||
|
if err = updateNginxConfig(constant.NginxScopeServer, []dto.NginxParam{{Name: "include", Params: []string{nginxInclude}}}, &website); err != nil {
|
||||||
|
global.LOG.Errorf("update nginx config failed, err: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func addMCPProxy(websiteID uint) error {
|
||||||
|
servers, _ := mcpServerRepo.List()
|
||||||
|
if len(servers) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
website, err := websiteRepo.GetFirst(commonRepo.WithByID(websiteID))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fileOp := files.NewFileOp()
|
||||||
|
includeDir := path.Join(nginxInstall.GetPath(), "www", "sites", website.Alias, "proxy")
|
||||||
|
if !fileOp.Stat(includeDir) {
|
||||||
|
if err = fileOp.CreateDir(includeDir, 0644); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
config, err := parser.NewStringParser(string(nginx_conf.SSE)).Parse()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
websiteDomain := website.Domains[0]
|
||||||
|
var baseUrl string
|
||||||
|
if website.Protocol == constant.ProtocolHTTP {
|
||||||
|
baseUrl = fmt.Sprintf("http://%s", websiteDomain.Domain)
|
||||||
|
} else {
|
||||||
|
baseUrl = fmt.Sprintf("https://%s", websiteDomain.Domain)
|
||||||
|
}
|
||||||
|
if websiteDomain.Port != 80 && websiteDomain.Port != 443 {
|
||||||
|
baseUrl = fmt.Sprintf("%s:%d", baseUrl, websiteDomain.Port)
|
||||||
|
}
|
||||||
|
for _, server := range servers {
|
||||||
|
includePath := path.Join(includeDir, server.Name+".conf")
|
||||||
|
config.FilePath = includePath
|
||||||
|
directives := config.Directives
|
||||||
|
location, ok := directives[0].(*components.Location)
|
||||||
|
if !ok {
|
||||||
|
err = errors.New("error")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
location.UpdateDirective("proxy_pass", []string{fmt.Sprintf("http://127.0.0.1:%d%s", server.Port, server.SsePath)})
|
||||||
|
location.ChangePath("^~", server.SsePath)
|
||||||
|
if err = nginx.WriteConfig(config, nginx.IndentedStyle); err != nil {
|
||||||
|
return buserr.WithErr(constant.ErrUpdateBuWebsite, err)
|
||||||
|
}
|
||||||
|
server.BaseURL = baseUrl
|
||||||
|
server.HostIP = "127.0.0.1"
|
||||||
|
go updateMcpServer(&server)
|
||||||
|
}
|
||||||
|
nginxInclude := fmt.Sprintf("/www/sites/%s/proxy/*.conf", website.Alias)
|
||||||
|
if err = updateNginxConfig(constant.NginxScopeServer, []dto.NginxParam{{Name: "include", Params: []string{nginxInclude}}}, &website); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateMcpServer(mcpServer *model.McpServer) error {
|
||||||
|
env := handleEnv(mcpServer)
|
||||||
|
if err := gotenv.Write(env, path.Join(mcpServer.Dir, ".env")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_ = mcpServerRepo.Save(mcpServer)
|
||||||
|
composePath := path.Join(constant.McpDir, mcpServer.Name, "docker-compose.yml")
|
||||||
|
_, _ = compose.Down(composePath)
|
||||||
|
if _, err := compose.Up(composePath); err != nil {
|
||||||
|
mcpServer.Status = constant.RuntimeError
|
||||||
|
mcpServer.Message = err.Error()
|
||||||
|
}
|
||||||
|
return mcpServerRepo.Save(mcpServer)
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleEnv(mcpServer *model.McpServer) gotenv.Env {
|
||||||
|
env := make(gotenv.Env)
|
||||||
|
env["CONTAINER_NAME"] = mcpServer.ContainerName
|
||||||
|
env["COMMAND"] = mcpServer.Command
|
||||||
|
env["PANEL_APP_PORT_HTTP"] = strconv.Itoa(mcpServer.Port)
|
||||||
|
env["BASE_URL"] = mcpServer.BaseURL
|
||||||
|
env["SSE_PATH"] = mcpServer.SsePath
|
||||||
|
env["HOST_IP"] = mcpServer.HostIP
|
||||||
|
envStr, _ := gotenv.Marshal(env)
|
||||||
|
mcpServer.Env = envStr
|
||||||
|
return env
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleCreateParams(mcpServer *model.McpServer, environments []request.Environment, volumes []request.Volume) error {
|
||||||
|
var composeContent []byte
|
||||||
|
if mcpServer.ID == 0 {
|
||||||
|
composeContent = mcp.DefaultMcpCompose
|
||||||
|
} else {
|
||||||
|
composeContent = []byte(mcpServer.DockerCompose)
|
||||||
|
}
|
||||||
|
composeMap := make(map[string]interface{})
|
||||||
|
if err := yaml.Unmarshal(composeContent, &composeMap); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
services, serviceValid := composeMap["services"].(map[string]interface{})
|
||||||
|
if !serviceValid {
|
||||||
|
return buserr.New(constant.ErrFileParse)
|
||||||
|
}
|
||||||
|
serviceName := ""
|
||||||
|
serviceValue := make(map[string]interface{})
|
||||||
|
|
||||||
|
if mcpServer.ID > 0 {
|
||||||
|
serviceName = mcpServer.Name
|
||||||
|
serviceValue = services[serviceName].(map[string]interface{})
|
||||||
|
} else {
|
||||||
|
for name, service := range services {
|
||||||
|
serviceName = name
|
||||||
|
serviceValue = service.(map[string]interface{})
|
||||||
|
break
|
||||||
|
}
|
||||||
|
delete(services, serviceName)
|
||||||
|
}
|
||||||
|
delete(serviceValue, "environment")
|
||||||
|
if len(environments) > 0 {
|
||||||
|
envMap := make(map[string]string)
|
||||||
|
for _, env := range environments {
|
||||||
|
envMap[env.Key] = env.Value
|
||||||
|
}
|
||||||
|
serviceValue["environment"] = envMap
|
||||||
|
}
|
||||||
|
delete(serviceValue, "volumes")
|
||||||
|
if len(volumes) > 0 {
|
||||||
|
volumeList := make([]string, 0)
|
||||||
|
for _, volume := range volumes {
|
||||||
|
volumeList = append(volumeList, fmt.Sprintf("%s:%s", volume.Source, volume.Target))
|
||||||
|
}
|
||||||
|
serviceValue["volumes"] = volumeList
|
||||||
|
}
|
||||||
|
|
||||||
|
services[mcpServer.Name] = serviceValue
|
||||||
|
composeByte, err := yaml.Marshal(composeMap)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
mcpServer.DockerCompose = string(composeByte)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func startMcp(mcpServer *model.McpServer) {
|
||||||
|
composePath := path.Join(constant.McpDir, mcpServer.Name, "docker-compose.yml")
|
||||||
|
if mcpServer.Status != constant.RuntimeNormal {
|
||||||
|
_, _ = compose.Down(composePath)
|
||||||
|
}
|
||||||
|
if out, err := compose.Up(composePath); err != nil {
|
||||||
|
mcpServer.Status = constant.RuntimeError
|
||||||
|
mcpServer.Message = out
|
||||||
|
} else {
|
||||||
|
mcpServer.Status = constant.RuntimeRunning
|
||||||
|
mcpServer.Message = ""
|
||||||
|
}
|
||||||
|
_ = syncMcpServerContainerStatus(mcpServer)
|
||||||
|
}
|
||||||
|
|
||||||
|
func syncMcpServerContainerStatus(mcpServer *model.McpServer) error {
|
||||||
|
containerNames := []string{mcpServer.ContainerName}
|
||||||
|
cli, err := docker.NewClient()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer cli.Close()
|
||||||
|
containers, err := cli.ListContainersByName(containerNames)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(containers) == 0 {
|
||||||
|
mcpServer.Status = constant.RuntimeStopped
|
||||||
|
return mcpServerRepo.Save(mcpServer)
|
||||||
|
}
|
||||||
|
container := containers[0]
|
||||||
|
switch container.State {
|
||||||
|
case "exited":
|
||||||
|
mcpServer.Status = constant.RuntimeError
|
||||||
|
case "running":
|
||||||
|
mcpServer.Status = constant.RuntimeRunning
|
||||||
|
case "paused":
|
||||||
|
mcpServer.Status = constant.RuntimeStopped
|
||||||
|
case "restarting":
|
||||||
|
mcpServer.Status = constant.RuntimeReStarting
|
||||||
|
default:
|
||||||
|
if mcpServer.Status != constant.RuntimeBuildIng {
|
||||||
|
mcpServer.Status = constant.RuntimeStopped
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mcpServerRepo.Save(mcpServer)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetWebsiteID() uint {
|
||||||
|
websiteID, _ := settingRepo.Get(settingRepo.WithByKey("MCP_WEBSITE_ID"))
|
||||||
|
if websiteID.Value == "" {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
websiteIDUint, _ := strconv.ParseUint(websiteID.Value, 10, 64)
|
||||||
|
return uint(websiteIDUint)
|
||||||
|
}
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/rsa"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
@@ -19,10 +21,10 @@ import (
|
|||||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||||
"github.com/1Panel-dev/1Panel/backend/global"
|
"github.com/1Panel-dev/1Panel/backend/global"
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/encrypt"
|
"github.com/1Panel-dev/1Panel/backend/utils/encrypt"
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/utils/systemctl"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/robfig/cron/v3"
|
"github.com/robfig/cron/v3"
|
||||||
)
|
)
|
||||||
@@ -42,6 +44,7 @@ type ISettingService interface {
|
|||||||
HandlePasswordExpired(c *gin.Context, old, new string) error
|
HandlePasswordExpired(c *gin.Context, old, new string) error
|
||||||
GenerateApiKey() (string, error)
|
GenerateApiKey() (string, error)
|
||||||
UpdateApiConfig(req dto.ApiInterfaceConfig) error
|
UpdateApiConfig(req dto.ApiInterfaceConfig) error
|
||||||
|
GenerateRSAKey() error
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewISettingService() ISettingService {
|
func NewISettingService() ISettingService {
|
||||||
@@ -163,7 +166,7 @@ func (u *SettingService) UpdateBindInfo(req dto.BindInfo) error {
|
|||||||
}
|
}
|
||||||
go func() {
|
go func() {
|
||||||
time.Sleep(1 * time.Second)
|
time.Sleep(1 * time.Second)
|
||||||
_, err := cmd.Exec("systemctl restart 1panel.service")
|
err := systemctl.Restart("1panel")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
global.LOG.Errorf("restart system with new bind info failed, err: %v", err)
|
global.LOG.Errorf("restart system with new bind info failed, err: %v", err)
|
||||||
}
|
}
|
||||||
@@ -211,7 +214,7 @@ func (u *SettingService) UpdatePort(port uint) error {
|
|||||||
}
|
}
|
||||||
go func() {
|
go func() {
|
||||||
time.Sleep(1 * time.Second)
|
time.Sleep(1 * time.Second)
|
||||||
_, err := cmd.Exec("systemctl restart 1panel.service")
|
err := systemctl.Restart("1panel")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
global.LOG.Errorf("restart system port failed, err: %v", err)
|
global.LOG.Errorf("restart system port failed, err: %v", err)
|
||||||
}
|
}
|
||||||
@@ -234,7 +237,7 @@ func (u *SettingService) UpdateSSL(c *gin.Context, req dto.SSLUpdate) error {
|
|||||||
c.SetCookie(constant.SessionName, sID, 0, "", "", false, true)
|
c.SetCookie(constant.SessionName, sID, 0, "", "", false, true)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
_, err := cmd.Exec("systemctl restart 1panel.service")
|
err := systemctl.Restart("1panel")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
global.LOG.Errorf("restart system failed, err: %v", err)
|
global.LOG.Errorf("restart system failed, err: %v", err)
|
||||||
}
|
}
|
||||||
@@ -332,7 +335,7 @@ func (u *SettingService) UpdateSSL(c *gin.Context, req dto.SSLUpdate) error {
|
|||||||
c.SetCookie(constant.SessionName, sID, 0, "", "", true, true)
|
c.SetCookie(constant.SessionName, sID, 0, "", "", true, true)
|
||||||
go func() {
|
go func() {
|
||||||
time.Sleep(1 * time.Second)
|
time.Sleep(1 * time.Second)
|
||||||
_, err := cmd.Exec("systemctl restart 1panel.service")
|
err := systemctl.Restart("1panel")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
global.LOG.Errorf("restart system failed, err: %v", err)
|
global.LOG.Errorf("restart system failed, err: %v", err)
|
||||||
}
|
}
|
||||||
@@ -510,5 +513,53 @@ func (u *SettingService) UpdateApiConfig(req dto.ApiInterfaceConfig) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
global.CONF.System.IpWhiteList = req.IpWhiteList
|
global.CONF.System.IpWhiteList = req.IpWhiteList
|
||||||
|
if err := settingRepo.Update("ApiKeyValidityTime", req.ApiKeyValidityTime); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
global.CONF.System.ApiKeyValidityTime = req.ApiKeyValidityTime
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func exportPrivateKeyToPEM(privateKey *rsa.PrivateKey) string {
|
||||||
|
privateKeyBytes := x509.MarshalPKCS1PrivateKey(privateKey)
|
||||||
|
privateKeyPEM := pem.EncodeToMemory(&pem.Block{
|
||||||
|
Type: "RSA PRIVATE KEY",
|
||||||
|
Bytes: privateKeyBytes,
|
||||||
|
})
|
||||||
|
return string(privateKeyPEM)
|
||||||
|
}
|
||||||
|
|
||||||
|
func exportPublicKeyToPEM(publicKey *rsa.PublicKey) (string, error) {
|
||||||
|
publicKeyBytes, err := x509.MarshalPKIXPublicKey(publicKey)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
publicKeyPEM := pem.EncodeToMemory(&pem.Block{
|
||||||
|
Type: "PUBLIC KEY",
|
||||||
|
Bytes: publicKeyBytes,
|
||||||
|
})
|
||||||
|
return string(publicKeyPEM), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *SettingService) GenerateRSAKey() error {
|
||||||
|
priKey, _ := settingRepo.Get(settingRepo.WithByKey("PASSWORD_PRIVATE_KEY"))
|
||||||
|
pubKey, _ := settingRepo.Get(settingRepo.WithByKey("PASSWORD_PUBLIC_KEY"))
|
||||||
|
if priKey.Value != "" && pubKey.Value != "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
privateKeyPEM := exportPrivateKeyToPEM(privateKey)
|
||||||
|
publicKeyPEM, _ := exportPublicKeyToPEM(&privateKey.PublicKey)
|
||||||
|
err = settingRepo.UpdateOrCreate("PASSWORD_PRIVATE_KEY", privateKeyPEM)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = settingRepo.UpdateOrCreate("PASSWORD_PUBLIC_KEY", publicKeyPEM)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user