2
0
mirror of https://github.com/acepanel/panel.git synced 2026-02-06 16:21:03 +08:00

feat(网站): 支持选择伪静态规则

This commit is contained in:
耗子
2024-11-28 23:51:01 +08:00
parent fec09652b7
commit 110b40edd7
16 changed files with 149 additions and 44 deletions

View File

@@ -30,5 +30,4 @@ type AppRepo interface {
UnInstall(slug string) error
Update(slug string) error
UpdateShow(slug string, show bool) error
UpdateCache() error
}

View File

@@ -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
}

View File

@@ -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)

View File

@@ -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

View File

@@ -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))
}

View File

@@ -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

View File

@@ -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")) {

View File

@@ -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

View File

@@ -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()

View File

@@ -29,6 +29,11 @@ func Cli() []*cli.Command {
Usage: "更新面板",
Action: cliService.Update,
},
{
Name: "sync",
Usage: "同步数据",
Action: cliService.Sync,
},
{
Name: "fix",
Usage: "修复面板",

View File

@@ -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)

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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 {

View File

@@ -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'),
// 保存默认配置

View File

@@ -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"