mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-09-30 14:26:36 +08:00
943818f7d4
将 OpenFlare 与平台业务的数据访问从 model 与 apps 直连迁入 repository, model 仅保留实体与无 IO 规则;补充 code-check 架构守卫与开发规范。
118 lines
4.5 KiB
Go
118 lines
4.5 KiB
Go
// Copyright 2026 Arctel.net
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package config_version
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"path"
|
|
"strings"
|
|
|
|
"github.com/Rain-kl/Wavelet/internal/repository"
|
|
|
|
"github.com/Rain-kl/Wavelet/internal/model"
|
|
"github.com/Rain-kl/Wavelet/pkg/pagesarchive"
|
|
openrestyrender "github.com/Rain-kl/Wavelet/pkg/render/openresty"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
const defaultPagesSnapshotEntryFile = "index.html"
|
|
const defaultPagesSnapshotFallbackPath = "/index.html"
|
|
|
|
func buildPagesRouteSnapshot(
|
|
ctx context.Context,
|
|
route *model.ProxyRoute,
|
|
) (originURL string, upstreams []string, pagesProjectID *uint, deployment *openrestyrender.PagesDeployment, err error) {
|
|
if route == nil {
|
|
return "", nil, nil, nil, errors.New("pages 路由配置无效")
|
|
}
|
|
if !repository.HasPagesProjectsTable(ctx) {
|
|
return "", nil, nil, nil, fmt.Errorf("路由 %s Pages 配置无效: pages 模块不可用", route.SiteName)
|
|
}
|
|
if route.PagesProjectID == nil || *route.PagesProjectID == 0 {
|
|
return "", nil, nil, nil, fmt.Errorf("路由 %s Pages 配置无效: 未绑定 Pages 项目", route.SiteName)
|
|
}
|
|
project, err := repository.GetPagesProjectByID(ctx, *route.PagesProjectID)
|
|
if err != nil {
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return "", nil, nil, nil, fmt.Errorf("路由 %s Pages 配置无效: pages 项目不存在", route.SiteName)
|
|
}
|
|
return "", nil, nil, nil, err
|
|
}
|
|
if !project.Enabled {
|
|
return "", nil, nil, nil, fmt.Errorf("路由 %s Pages 配置无效: pages 项目未启用", route.SiteName)
|
|
}
|
|
if project.ActiveDeploymentID == nil || *project.ActiveDeploymentID == 0 {
|
|
return "", nil, nil, nil, fmt.Errorf("路由 %s Pages 配置无效: pages 项目没有激活部署", route.SiteName)
|
|
}
|
|
activeDeployment, err := repository.GetPagesDeploymentByID(ctx, *project.ActiveDeploymentID)
|
|
if err != nil {
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return "", nil, nil, nil, fmt.Errorf("路由 %s Pages 配置无效: pages 激活部署不存在", route.SiteName)
|
|
}
|
|
return "", nil, nil, nil, err
|
|
}
|
|
if activeDeployment.ProjectID != project.ID {
|
|
return "", nil, nil, nil, fmt.Errorf("路由 %s Pages 配置无效: pages 激活部署不匹配", route.SiteName)
|
|
}
|
|
if strings.TrimSpace(activeDeployment.Checksum) == "" {
|
|
return "", nil, nil, nil, fmt.Errorf("路由 %s Pages 配置无效: pages 部署校验和缺失", route.SiteName)
|
|
}
|
|
|
|
pagesProjectID = route.PagesProjectID
|
|
deployment, err = buildSnapshotPagesDeployment(project, activeDeployment)
|
|
if err != nil {
|
|
return "", nil, nil, nil, fmt.Errorf("路由 %s Pages 配置无效: %w", route.SiteName, err)
|
|
}
|
|
originURL = fmt.Sprintf("openflare-pages://project/%d", project.ID)
|
|
return originURL, []string{originURL}, pagesProjectID, deployment, nil
|
|
}
|
|
|
|
func buildSnapshotPagesDeployment(
|
|
project *model.PagesProject,
|
|
activeDeployment *model.PagesDeployment,
|
|
) (*openrestyrender.PagesDeployment, error) {
|
|
if project == nil || activeDeployment == nil {
|
|
return nil, errors.New("pages 项目或部署为空")
|
|
}
|
|
rootDir, err := pagesarchive.NormalizeLogicalPath(strings.TrimSpace(project.RootDir), true)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("pages 根目录不合法: %w", err)
|
|
}
|
|
entryFile := strings.TrimSpace(project.EntryFile)
|
|
if entryFile == "" {
|
|
entryFile = defaultPagesSnapshotEntryFile
|
|
}
|
|
entryFile, err = pagesarchive.NormalizeLogicalPath(entryFile, false)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("pages 入口文件不合法: %w", err)
|
|
}
|
|
fallbackPath := strings.TrimSpace(project.SPAFallbackPath)
|
|
if fallbackPath == "" {
|
|
fallbackPath = defaultPagesSnapshotFallbackPath
|
|
}
|
|
localRoot := openrestyrender.PagesProjectLocalRoot(project.ID)
|
|
if rootDir != "" {
|
|
localRoot = path.Join(localRoot, rootDir)
|
|
}
|
|
return &openrestyrender.PagesDeployment{
|
|
ProjectID: project.ID,
|
|
ProjectSlug: strings.TrimSpace(project.Slug),
|
|
DeploymentID: activeDeployment.ID,
|
|
DeploymentNumber: activeDeployment.DeploymentNumber,
|
|
Checksum: strings.TrimSpace(activeDeployment.Checksum),
|
|
EntryFile: entryFile,
|
|
SPAFallbackEnabled: project.SPAFallbackEnabled,
|
|
SPAFallbackPath: fallbackPath,
|
|
APIProxyEnabled: project.APIProxyEnabled,
|
|
APIProxyPath: strings.TrimSpace(project.APIProxyPath),
|
|
APIProxyPass: strings.TrimSpace(project.APIProxyPass),
|
|
APIProxyRewrite: strings.TrimSpace(project.APIProxyRewrite),
|
|
// Root is project-scoped so Agents can swap active packages without
|
|
// re-publishing main config (nginx root stays stable).
|
|
LocalRoot: localRoot,
|
|
}, nil
|
|
}
|