mirror of
https://github.com/acepanel/panel.git
synced 2026-02-06 16:21:03 +08:00
feat(网站): 支持选择伪静态规则
This commit is contained in:
@@ -30,5 +30,4 @@ type AppRepo interface {
|
||||
UnInstall(slug string) error
|
||||
Update(slug string) error
|
||||
UpdateShow(slug string, show bool) error
|
||||
UpdateCache() error
|
||||
}
|
||||
|
||||
@@ -19,4 +19,6 @@ type Cache struct {
|
||||
type CacheRepo interface {
|
||||
Get(key CacheKey, defaultValue ...string) (string, error)
|
||||
Set(key CacheKey, value string) error
|
||||
UpdateApps() error
|
||||
UpdateRewrites() error
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ type Website struct {
|
||||
}
|
||||
|
||||
type WebsiteRepo interface {
|
||||
GetRewrites() (map[string]string, error)
|
||||
UpdateDefaultConfig(req *request.WebsiteDefaultConfig) error
|
||||
Count() (int64, error)
|
||||
Get(id uint) (*types.WebsiteSetting, error)
|
||||
|
||||
@@ -15,13 +15,10 @@ import (
|
||||
"github.com/TheTNB/panel/internal/app"
|
||||
"github.com/TheTNB/panel/internal/biz"
|
||||
"github.com/TheTNB/panel/pkg/api"
|
||||
"github.com/TheTNB/panel/pkg/apploader"
|
||||
"github.com/TheTNB/panel/pkg/shell"
|
||||
)
|
||||
|
||||
type appRepo struct {
|
||||
api *api.API
|
||||
}
|
||||
type appRepo struct{}
|
||||
|
||||
func NewAppRepo() biz.AppRepo {
|
||||
return do.MustInvoke[biz.AppRepo](injector)
|
||||
@@ -309,26 +306,6 @@ func (r *appRepo) UpdateShow(slug string, show bool) error {
|
||||
return app.Orm.Save(item).Error
|
||||
}
|
||||
|
||||
func (r *appRepo) UpdateCache() error {
|
||||
remote, err := r.api.Apps()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 去除本地不存在的应用
|
||||
*remote = slices.Clip(slices.DeleteFunc(*remote, func(app *api.App) bool {
|
||||
_, err = apploader.Get(app.Slug)
|
||||
return err != nil
|
||||
}))
|
||||
|
||||
encoded, err := json.Marshal(remote)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return NewCacheRepo().Set(biz.CacheKeyApps, string(encoded))
|
||||
}
|
||||
|
||||
func (r *appRepo) preCheck(app *api.App) error {
|
||||
var apps []string
|
||||
var installed []string
|
||||
|
||||
@@ -1,16 +1,22 @@
|
||||
package data
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"slices"
|
||||
|
||||
"github.com/samber/do/v2"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/TheTNB/panel/internal/app"
|
||||
"github.com/TheTNB/panel/internal/biz"
|
||||
"github.com/TheTNB/panel/pkg/api"
|
||||
"github.com/TheTNB/panel/pkg/apploader"
|
||||
)
|
||||
|
||||
type cacheRepo struct{}
|
||||
type cacheRepo struct {
|
||||
api *api.API
|
||||
}
|
||||
|
||||
func NewCacheRepo() biz.CacheRepo {
|
||||
return do.MustInvoke[biz.CacheRepo](injector)
|
||||
@@ -40,3 +46,37 @@ func (r *cacheRepo) Set(key biz.CacheKey, value string) error {
|
||||
cache.Value = value
|
||||
return app.Orm.Save(cache).Error
|
||||
}
|
||||
|
||||
func (r *cacheRepo) UpdateApps() error {
|
||||
remote, err := r.api.Apps()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 去除本地不存在的应用
|
||||
*remote = slices.Clip(slices.DeleteFunc(*remote, func(app *api.App) bool {
|
||||
_, err = apploader.Get(app.Slug)
|
||||
return err != nil
|
||||
}))
|
||||
|
||||
encoded, err := json.Marshal(remote)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return r.Set(biz.CacheKeyApps, string(encoded))
|
||||
}
|
||||
|
||||
func (r *cacheRepo) UpdateRewrites() error {
|
||||
rewrites, err := r.api.RewritesByType("nginx")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
encoded, err := json.Marshal(rewrites)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return r.Set(biz.CacheKeyRewrites, string(encoded))
|
||||
}
|
||||
|
||||
@@ -20,15 +20,15 @@ var injector = do.New()
|
||||
|
||||
func init() {
|
||||
do.Provide(injector, func(i do.Injector) (biz.AppRepo, error) {
|
||||
return &appRepo{
|
||||
api: api.NewAPI(app.Version),
|
||||
}, nil
|
||||
return &appRepo{}, nil
|
||||
})
|
||||
do.Provide(injector, func(i do.Injector) (biz.BackupRepo, error) {
|
||||
return &backupRepo{}, nil
|
||||
})
|
||||
do.Provide(injector, func(i do.Injector) (biz.CacheRepo, error) {
|
||||
return &cacheRepo{}, nil
|
||||
return &cacheRepo{
|
||||
api: api.NewAPI(app.Version),
|
||||
}, nil
|
||||
})
|
||||
do.Provide(injector, func(i do.Injector) (biz.CertRepo, error) {
|
||||
return &certRepo{}, nil
|
||||
|
||||
@@ -378,6 +378,7 @@ func (r *settingRepo) FixPanel() error {
|
||||
if app.IsCli {
|
||||
fmt.Println("|-开始修复面板...")
|
||||
}
|
||||
|
||||
// 检查关键文件是否正常
|
||||
flag := false
|
||||
if !io.Exists(filepath.Join(app.Root, "panel", "web")) {
|
||||
|
||||
@@ -2,6 +2,7 @@ package data
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
@@ -18,6 +19,7 @@ import (
|
||||
"github.com/TheTNB/panel/internal/embed"
|
||||
"github.com/TheTNB/panel/internal/http/request"
|
||||
"github.com/TheTNB/panel/pkg/acme"
|
||||
"github.com/TheTNB/panel/pkg/api"
|
||||
"github.com/TheTNB/panel/pkg/cert"
|
||||
"github.com/TheTNB/panel/pkg/io"
|
||||
"github.com/TheTNB/panel/pkg/nginx"
|
||||
@@ -33,6 +35,25 @@ func NewWebsiteRepo() biz.WebsiteRepo {
|
||||
return do.MustInvoke[biz.WebsiteRepo](injector)
|
||||
}
|
||||
|
||||
func (r *websiteRepo) GetRewrites() (map[string]string, error) {
|
||||
cached, err := NewCacheRepo().Get(biz.CacheKeyRewrites)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var rewrites api.Rewrites
|
||||
if err = json.Unmarshal([]byte(cached), &rewrites); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rw := make(map[string]string)
|
||||
for rewrite := range slices.Values(rewrites) {
|
||||
rw[rewrite.Name] = rewrite.Content
|
||||
}
|
||||
|
||||
return rw, nil
|
||||
}
|
||||
|
||||
func (r *websiteRepo) UpdateDefaultConfig(req *request.WebsiteDefaultConfig) error {
|
||||
if err := io.Write(filepath.Join(app.Root, "server/nginx/html/index.html"), req.Index, 0644); err != nil {
|
||||
return err
|
||||
|
||||
@@ -14,15 +14,15 @@ import (
|
||||
|
||||
// PanelTask 面板每日任务
|
||||
type PanelTask struct {
|
||||
appRepo biz.AppRepo
|
||||
backupRepo biz.BackupRepo
|
||||
cacheRepo biz.CacheRepo
|
||||
settingRepo biz.SettingRepo
|
||||
}
|
||||
|
||||
func NewPanelTask() *PanelTask {
|
||||
return &PanelTask{
|
||||
appRepo: data.NewAppRepo(),
|
||||
backupRepo: data.NewBackupRepo(),
|
||||
cacheRepo: data.NewCacheRepo(),
|
||||
settingRepo: data.NewSettingRepo(),
|
||||
}
|
||||
}
|
||||
@@ -56,12 +56,21 @@ func (r *PanelTask) Run() {
|
||||
// 更新商店缓存
|
||||
time.AfterFunc(time.Duration(rand.IntN(300))*time.Second, func() {
|
||||
if offline, err := r.settingRepo.GetBool(biz.SettingKeyOfflineMode); err == nil && !offline {
|
||||
if err = r.appRepo.UpdateCache(); err != nil {
|
||||
if err = r.cacheRepo.UpdateApps(); err != nil {
|
||||
app.Logger.Warn("更新商店缓存失败", slog.Any("err", err))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// 更新伪静态缓存
|
||||
time.AfterFunc(time.Duration(rand.IntN(300))*time.Second, func() {
|
||||
if offline, err := r.settingRepo.GetBool(biz.SettingKeyOfflineMode); err == nil && !offline {
|
||||
if err = r.cacheRepo.UpdateRewrites(); err != nil {
|
||||
app.Logger.Warn("更新伪静态缓存失败", slog.Any("err", err))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// 回收内存
|
||||
runtime.GC()
|
||||
debug.FreeOSMemory()
|
||||
|
||||
@@ -29,6 +29,11 @@ func Cli() []*cli.Command {
|
||||
Usage: "更新面板",
|
||||
Action: cliService.Update,
|
||||
},
|
||||
{
|
||||
Name: "sync",
|
||||
Usage: "同步数据",
|
||||
Action: cliService.Sync,
|
||||
},
|
||||
{
|
||||
Name: "fix",
|
||||
Usage: "修复面板",
|
||||
|
||||
@@ -48,6 +48,7 @@ func Http(r chi.Router) {
|
||||
|
||||
r.Route("/website", func(r chi.Router) {
|
||||
website := service.NewWebsiteService()
|
||||
r.Get("/rewrites", website.GetRewrites)
|
||||
r.Get("/defaultConfig", website.GetDefaultConfig)
|
||||
r.Post("/defaultConfig", website.UpdateDefaultConfig)
|
||||
r.Get("/", website.List)
|
||||
|
||||
@@ -13,12 +13,14 @@ import (
|
||||
|
||||
type AppService struct {
|
||||
appRepo biz.AppRepo
|
||||
cacheRepo biz.CacheRepo
|
||||
settingRepo biz.SettingRepo
|
||||
}
|
||||
|
||||
func NewAppService() *AppService {
|
||||
return &AppService{
|
||||
appRepo: data.NewAppRepo(),
|
||||
cacheRepo: data.NewCacheRepo(),
|
||||
settingRepo: data.NewSettingRepo(),
|
||||
}
|
||||
}
|
||||
@@ -170,7 +172,7 @@ func (s *AppService) UpdateCache(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
if err := s.appRepo.UpdateCache(); err != nil {
|
||||
if err := s.cacheRepo.UpdateApps(); err != nil {
|
||||
Error(w, http.StatusInternalServerError, "%v", err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ type CliService struct {
|
||||
hr string
|
||||
api *api.API
|
||||
appRepo biz.AppRepo
|
||||
cacheRepo biz.CacheRepo
|
||||
userRepo biz.UserRepo
|
||||
settingRepo biz.SettingRepo
|
||||
backupRepo biz.BackupRepo
|
||||
@@ -47,6 +48,7 @@ func NewCliService() *CliService {
|
||||
hr: `+----------------------------------------------------`,
|
||||
api: api.NewAPI(app.Version),
|
||||
appRepo: data.NewAppRepo(),
|
||||
cacheRepo: data.NewCacheRepo(),
|
||||
userRepo: data.NewUserRepo(),
|
||||
settingRepo: data.NewSettingRepo(),
|
||||
backupRepo: data.NewBackupRepo(),
|
||||
@@ -98,6 +100,18 @@ func (s *CliService) Update(ctx context.Context, cmd *cli.Command) error {
|
||||
return s.settingRepo.UpdatePanel(ver, url, checksum)
|
||||
}
|
||||
|
||||
func (s *CliService) Sync(ctx context.Context, cmd *cli.Command) error {
|
||||
if err := s.cacheRepo.UpdateApps(); err != nil {
|
||||
return fmt.Errorf("同步应用数据失败:%v", err)
|
||||
}
|
||||
if err := s.cacheRepo.UpdateRewrites(); err != nil {
|
||||
return fmt.Errorf("同步伪静态规则失败:%v", err)
|
||||
}
|
||||
|
||||
fmt.Println("数据同步成功")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *CliService) Fix(ctx context.Context, cmd *cli.Command) error {
|
||||
return s.settingRepo.FixPanel()
|
||||
}
|
||||
@@ -847,6 +861,8 @@ func (s *CliService) Init(ctx context.Context, cmd *cli.Command) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// 初始化应用中心缓存
|
||||
return s.appRepo.UpdateCache()
|
||||
// 初始化缓存
|
||||
_ = s.cacheRepo.UpdateApps()
|
||||
_ = s.cacheRepo.UpdateRewrites()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -25,6 +25,16 @@ func NewWebsiteService() *WebsiteService {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *WebsiteService) GetRewrites(w http.ResponseWriter, r *http.Request) {
|
||||
rewrites, err := s.websiteRepo.GetRewrites()
|
||||
if err != nil {
|
||||
Error(w, http.StatusInternalServerError, "%v", err)
|
||||
return
|
||||
}
|
||||
|
||||
Success(w, rewrites)
|
||||
}
|
||||
|
||||
func (s *WebsiteService) GetDefaultConfig(w http.ResponseWriter, r *http.Request) {
|
||||
index, err := io.Read(filepath.Join(app.Root, "server/nginx/html/index.html"))
|
||||
if err != nil {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { AxiosResponse } from 'axios'
|
||||
|
||||
import { request } from '@/utils'
|
||||
import { http, request } from '@/utils'
|
||||
|
||||
export default {
|
||||
// 列表
|
||||
@@ -11,6 +11,8 @@ export default {
|
||||
// 删除
|
||||
delete: (id: number, path: boolean, db: boolean): Promise<AxiosResponse<any>> =>
|
||||
request.delete(`/website/${id}`, { data: { path, db } }),
|
||||
// 伪静态
|
||||
rewrites: () => http.Get(`/website/rewrites`),
|
||||
// 获取默认配置
|
||||
defaultConfig: (): Promise<AxiosResponse<any>> => request.get('/website/defaultConfig'),
|
||||
// 保存默认配置
|
||||
|
||||
@@ -59,6 +59,16 @@ const installedDbAndPhp = ref({
|
||||
]
|
||||
})
|
||||
const certs = ref<Cert[]>([] as Cert[])
|
||||
const { data: rewrites }: { data: any } = useRequest(website.rewrites, {
|
||||
initialData: {}
|
||||
})
|
||||
const rewriteOptions = computed(() => {
|
||||
return Object.keys(rewrites.value).map((key) => ({
|
||||
label: key,
|
||||
value: key
|
||||
}))
|
||||
})
|
||||
const rewriteValue = ref(null)
|
||||
|
||||
const title = computed(() => {
|
||||
if (setting.value) {
|
||||
@@ -121,6 +131,10 @@ const handleReset = async () => {
|
||||
})
|
||||
}
|
||||
|
||||
const handleRewrite = (value: string) => {
|
||||
setting.value.rewrite = rewrites.value[value] || ''
|
||||
}
|
||||
|
||||
const handleObtainCert = async () => {
|
||||
messageReactive = window.$message.loading('请稍后...', {
|
||||
duration: 0
|
||||
@@ -239,13 +253,13 @@ onMounted(async () => {
|
||||
<n-form-item label="运行目录">
|
||||
<n-input
|
||||
v-model:value="setting.root"
|
||||
placeholder="输入运行目录(Laravel等程序需要)(绝对路径)"
|
||||
placeholder="输入运行目录(Laravel 等程序需要)(绝对路径)"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item label="默认文档">
|
||||
<n-dynamic-tags v-model:value="setting.index" />
|
||||
</n-form-item>
|
||||
<n-form-item label="PHP版本">
|
||||
<n-form-item label="PHP 版本">
|
||||
<n-select
|
||||
v-model:value="setting.php"
|
||||
:default-value="0"
|
||||
@@ -339,11 +353,16 @@ onMounted(async () => {
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="rewrite" tab="伪静态">
|
||||
<n-flex vertical>
|
||||
<n-alert type="info" w-full>
|
||||
设置伪静态规则,填入
|
||||
<n-tag>location</n-tag>
|
||||
部分即可
|
||||
</n-alert>
|
||||
<n-form label-placement="left" label-width="auto">
|
||||
<n-form-item label="预设">
|
||||
<n-select
|
||||
v-model:value="rewriteValue"
|
||||
clearable
|
||||
:options="rewriteOptions"
|
||||
@update-value="handleRewrite"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
<Editor
|
||||
v-if="setting"
|
||||
v-model:value="setting.rewrite"
|
||||
|
||||
Reference in New Issue
Block a user