Skip to content

Commit 078d7fb

Browse files
feat: Add AI-enhanced configuration (#7870)
1 parent c709e48 commit 078d7fb

File tree

31 files changed

+2138
-156
lines changed

31 files changed

+2138
-156
lines changed

backend/app/api/v1/ai_tool.go

+61
Original file line numberDiff line numberDiff line change
@@ -134,3 +134,64 @@ func (b *BaseApi) LoadGpuInfo(c *gin.Context) {
134134
}
135135
helper.SuccessWithData(c, &common.GpuInfo{})
136136
}
137+
138+
// @Tags AITools
139+
// @Summary Bind domain
140+
// @Accept json
141+
// @Param request body dto.WebsiteConfig true "request"
142+
// @Success 200
143+
// @Security ApiKeyAuth
144+
// @Security Timestamp
145+
// @Router /aitool/domain/bind [post]
146+
func (b *BaseApi) BindDomain(c *gin.Context) {
147+
var req dto.OllamaBindDomain
148+
if err := helper.CheckBindAndValidate(&req, c); err != nil {
149+
return
150+
}
151+
if err := AIToolService.BindDomain(req); err != nil {
152+
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
153+
return
154+
}
155+
helper.SuccessWithOutData(c)
156+
}
157+
158+
// @Tags AITools
159+
// @Summary Get bind domain
160+
// @Accept json
161+
// @Param request body dto.OllamaBindDomainReq true "request"
162+
// @Success 200 {object} dto.OllamaBindDomainRes
163+
// @Security ApiKeyAuth
164+
// @Security Timestamp
165+
// @Router /aitool/domain/get [post]
166+
func (b *BaseApi) GetBindDomain(c *gin.Context) {
167+
var req dto.OllamaBindDomainReq
168+
if err := helper.CheckBindAndValidate(&req, c); err != nil {
169+
return
170+
}
171+
res, err := AIToolService.GetBindDomain(req)
172+
if err != nil {
173+
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
174+
return
175+
}
176+
helper.SuccessWithData(c, res)
177+
}
178+
179+
// Tags AITools
180+
// Summary Update bind domain
181+
// Accept json
182+
// Param request body dto.OllamaBindDomain true "request"
183+
// Success 200
184+
// Security ApiKeyAuth
185+
// Security Timestamp
186+
// Router /aitool/domain/update [post]
187+
func (b *BaseApi) UpdateBindDomain(c *gin.Context) {
188+
var req dto.OllamaBindDomain
189+
if err := helper.CheckBindAndValidate(&req, c); err != nil {
190+
return
191+
}
192+
if err := AIToolService.UpdateBindDomain(req); err != nil {
193+
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
194+
return
195+
}
196+
helper.SuccessWithOutData(c)
197+
}

backend/app/dto/ai_tool.go

+19
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,22 @@ type OllamaModelInfo struct {
99
type OllamaModelName struct {
1010
Name string `json:"name"`
1111
}
12+
13+
type OllamaBindDomain struct {
14+
Domain string `json:"domain" validate:"required"`
15+
AppInstallID uint `json:"appInstallID" validate:"required"`
16+
SSLID uint `json:"sslID"`
17+
AllowIPs []string `json:"allowIPs"`
18+
WebsiteID uint `json:"websiteID"`
19+
}
20+
21+
type OllamaBindDomainReq struct {
22+
AppInstallID uint `json:"appInstallID" validate:"required"`
23+
}
24+
25+
type OllamaBindDomainRes struct {
26+
Domain string `json:"domain"`
27+
SSLID uint `json:"sslID"`
28+
AllowIPs []string `json:"allowIPs"`
29+
WebsiteID uint `json:"websiteID"`
30+
}

backend/app/service/ai_tool.go

+100
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package service
22

33
import (
4+
"context"
45
"fmt"
6+
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
57
"io"
68
"os"
79
"os/exec"
@@ -22,6 +24,9 @@ type IAIToolService interface {
2224
Create(name string) error
2325
Delete(name string) error
2426
LoadDetail(name string) (string, error)
27+
BindDomain(req dto.OllamaBindDomain) error
28+
GetBindDomain(req dto.OllamaBindDomainReq) (*dto.OllamaBindDomainRes, error)
29+
UpdateBindDomain(req dto.OllamaBindDomain) error
2530
}
2631

2732
func NewIAIToolService() IAIToolService {
@@ -192,3 +197,98 @@ func (u *AIToolService) Delete(name string) error {
192197
}
193198
return nil
194199
}
200+
201+
func (u *AIToolService) BindDomain(req dto.OllamaBindDomain) error {
202+
nginxInstall, _ := getAppInstallByKey(constant.AppOpenresty)
203+
if nginxInstall.ID == 0 {
204+
return buserr.New("ErrOpenrestyInstall")
205+
}
206+
createWebsiteReq := request.WebsiteCreate{
207+
PrimaryDomain: req.Domain,
208+
Alias: strings.ToLower(req.Domain),
209+
Type: constant.Deployment,
210+
AppType: constant.InstalledApp,
211+
AppInstallID: req.AppInstallID,
212+
}
213+
websiteService := NewIWebsiteService()
214+
if err := websiteService.CreateWebsite(createWebsiteReq); err != nil {
215+
return err
216+
}
217+
website, err := websiteRepo.GetFirst(websiteRepo.WithAlias(strings.ToLower(req.Domain)))
218+
if err != nil {
219+
return err
220+
}
221+
if err = ConfigAllowIPs(req.AllowIPs, website); err != nil {
222+
return err
223+
}
224+
if req.SSLID > 0 {
225+
sslReq := request.WebsiteHTTPSOp{
226+
WebsiteID: website.ID,
227+
Enable: true,
228+
Type: "existed",
229+
WebsiteSSLID: req.SSLID,
230+
HttpConfig: "HTTPSOnly",
231+
}
232+
if _, err = websiteService.OpWebsiteHTTPS(context.Background(), sslReq); err != nil {
233+
return err
234+
}
235+
}
236+
return nil
237+
}
238+
239+
func (u *AIToolService) GetBindDomain(req dto.OllamaBindDomainReq) (*dto.OllamaBindDomainRes, error) {
240+
install, err := appInstallRepo.GetFirst(commonRepo.WithByID(req.AppInstallID))
241+
if err != nil {
242+
return nil, err
243+
}
244+
res := &dto.OllamaBindDomainRes{}
245+
website, _ := websiteRepo.GetFirst(websiteRepo.WithAppInstallId(install.ID))
246+
if website.ID == 0 {
247+
return res, nil
248+
}
249+
res.WebsiteID = website.ID
250+
res.Domain = website.PrimaryDomain
251+
if website.WebsiteSSLID > 0 {
252+
res.SSLID = website.WebsiteSSLID
253+
}
254+
res.AllowIPs = GetAllowIps(website)
255+
return res, nil
256+
}
257+
258+
func (u *AIToolService) UpdateBindDomain(req dto.OllamaBindDomain) error {
259+
nginxInstall, _ := getAppInstallByKey(constant.AppOpenresty)
260+
if nginxInstall.ID == 0 {
261+
return buserr.New("ErrOpenrestyInstall")
262+
}
263+
websiteService := NewIWebsiteService()
264+
website, err := websiteRepo.GetFirst(commonRepo.WithByID(req.WebsiteID))
265+
if err != nil {
266+
return err
267+
}
268+
if err = ConfigAllowIPs(req.AllowIPs, website); err != nil {
269+
return err
270+
}
271+
if req.SSLID > 0 {
272+
sslReq := request.WebsiteHTTPSOp{
273+
WebsiteID: website.ID,
274+
Enable: true,
275+
Type: "existed",
276+
WebsiteSSLID: req.SSLID,
277+
HttpConfig: "HTTPSOnly",
278+
}
279+
if _, err = websiteService.OpWebsiteHTTPS(context.Background(), sslReq); err != nil {
280+
return err
281+
}
282+
return nil
283+
}
284+
if website.WebsiteSSLID > 0 && req.SSLID == 0 {
285+
sslReq := request.WebsiteHTTPSOp{
286+
WebsiteID: website.ID,
287+
Enable: false,
288+
}
289+
if _, err = websiteService.OpWebsiteHTTPS(context.Background(), sslReq); err != nil {
290+
return err
291+
}
292+
}
293+
return nil
294+
}

backend/app/service/website_utils.go

+58
Original file line numberDiff line numberDiff line change
@@ -642,9 +642,15 @@ func applySSL(website model.Website, websiteSSL model.WebsiteSSL, req request.We
642642
}
643643
if param.Name == "ssl_protocols" {
644644
nginxParams[i].Params = req.SSLProtocol
645+
if len(req.SSLProtocol) == 0 {
646+
nginxParams[i].Params = []string{"TLSv1.3", "TLSv1.2", "TLSv1.1", "TLSv1"}
647+
}
645648
}
646649
if param.Name == "ssl_ciphers" {
647650
nginxParams[i].Params = []string{req.Algorithm}
651+
if len(req.Algorithm) == 0 {
652+
nginxParams[i].Params = []string{"ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:!aNULL:!eNULL:!EXPORT:!DSS:!DES:!RC4:!3DES:!MD5:!PSK:!KRB5:!SRP:!CAMELLIA:!SEED"}
653+
}
648654
}
649655
}
650656
if req.Hsts {
@@ -1106,3 +1112,55 @@ func getResourceContent(fileOp files.FileOp, resourcePath string) (string, error
11061112
}
11071113
return "", nil
11081114
}
1115+
1116+
func ConfigAllowIPs(ips []string, website model.Website) error {
1117+
nginxFull, err := getNginxFull(&website)
1118+
if err != nil {
1119+
return err
1120+
}
1121+
nginxConfig := nginxFull.SiteConfig
1122+
config := nginxFull.SiteConfig.Config
1123+
server := config.FindServers()[0]
1124+
server.RemoveDirective("allow", nil)
1125+
server.RemoveDirective("deny", nil)
1126+
if len(ips) > 0 {
1127+
server.UpdateAllowIPs(ips)
1128+
}
1129+
if err := nginx.WriteConfig(config, nginx.IndentedStyle); err != nil {
1130+
return err
1131+
}
1132+
return nginxCheckAndReload(nginxConfig.OldContent, config.FilePath, nginxFull.Install.ContainerName)
1133+
}
1134+
1135+
func GetAllowIps(website model.Website) []string {
1136+
nginxFull, err := getNginxFull(&website)
1137+
if err != nil {
1138+
return nil
1139+
}
1140+
config := nginxFull.SiteConfig.Config
1141+
server := config.FindServers()[0]
1142+
dirs := server.GetDirectives()
1143+
var ips []string
1144+
for _, dir := range dirs {
1145+
if dir.GetName() == "allow" {
1146+
ips = append(ips, dir.GetParameters()...)
1147+
}
1148+
}
1149+
return ips
1150+
}
1151+
1152+
func ConfigAIProxy(website model.Website) error {
1153+
nginxFull, err := getNginxFull(&website)
1154+
if err != nil {
1155+
return nil
1156+
}
1157+
config := nginxFull.SiteConfig.Config
1158+
server := config.FindServers()[0]
1159+
dirs := server.GetDirectives()
1160+
for _, dir := range dirs {
1161+
if dir.GetName() == "location" && dir.GetParameters()[0] == "/" {
1162+
server.UpdateRootProxy()
1163+
}
1164+
}
1165+
return nil
1166+
}

backend/i18n/lang/en.yaml

+3
Original file line numberDiff line numberDiff line change
@@ -284,3 +284,6 @@ UserInfoPassHelp: "Tip: To change the password, you can execute the command: "
284284
DBConnErr: "Error: Failed to initialize database connection, {{ .err }}"
285285
SystemVersion: "version: "
286286
SystemMode: "mode: "
287+
288+
#ai-tool
289+
ErrOpenrestyInstall: 'Please install Openresty first'

backend/i18n/lang/ja.yaml

+3
Original file line numberDiff line numberDiff line change
@@ -281,3 +281,6 @@ UserInfoPassHelp: "ヒント:パスワードを変更するには、コマン
281281
DBConnErr: "エラー:データベース接続の初期化に失敗しました、{{.err}}"
282282
SystemVersion: "バージョン:"
283283
SystemMode: "モード:"
284+
285+
#ai-tool
286+
ErrOpenrestyInstall: 'まず Openresty をインストールしてください'

backend/i18n/lang/ko.yaml

+3
Original file line numberDiff line numberDiff line change
@@ -284,3 +284,6 @@ UserInfoPassHelp: "팁: 비밀번호를 변경하려면 다음 명령어를 실
284284
DBConnErr: "오류: 데이터베이스 연결 초기화 실패 {{ .err }}"
285285
SystemVersion: "버전: "
286286
SystemMode: "모드: "
287+
288+
#ai-tool
289+
ErrOpenrestyInstall: '먼저 Openresty를 설치하세요'

backend/i18n/lang/ms.yml

+3
Original file line numberDiff line numberDiff line change
@@ -283,3 +283,6 @@ UserInfoPassHelp: "Petua: Untuk menukar kata laluan, anda boleh menjalankan arah
283283
DBConnErr: "Ralat: Gagal memulakan sambungan pangkalan data, {{ .err }}"
284284
SystemVersion: "Versi: "
285285
SystemMode: "Mod: "
286+
287+
#ai-tool
288+
ErrOpenrestyInstall: 'Sila pasang Openresty terlebih dahulu'

backend/i18n/lang/pt-BR.yaml

+4-1
Original file line numberDiff line numberDiff line change
@@ -280,4 +280,7 @@ UserInfoAddr: "Endereço do painel: "
280280
UserInfoPassHelp: "Dica: Para alterar a senha, você pode executar o comando: "
281281
DBConnErr: "Erro: Falha ao inicializar a conexão com o banco de dados, {{ .err }}"
282282
SystemVersion: "versão: "
283-
SystemMode: "modo: "
283+
SystemMode: "modo: "
284+
285+
#ai-tool
286+
ErrOpenrestyInstall: 'Por favor, instale o Openresty primeiro'

backend/i18n/lang/pt.yaml

-63
This file was deleted.

backend/i18n/lang/ru.yaml

+3
Original file line numberDiff line numberDiff line change
@@ -284,3 +284,6 @@ UserInfoPassHelp: "Подсказка: чтобы изменить пароль,
284284
DBConnErr: "Ошибка: не удалось инициализировать подключение к базе данных, {{ .err }}"
285285
SystemVersion: "версия: "
286286
SystemMode: "режим: "
287+
288+
#ai-tool
289+
"ErrOpenrestyInstall": "Пожалуйста, установите Openresty сначала"

0 commit comments

Comments
 (0)