mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-10-12 18:26:36 +08:00
feat(cmd): assemble control plane via Wavelet plugins plus server
This commit is contained in:
@@ -3,17 +3,14 @@
|
||||
|
||||
package apiutil
|
||||
|
||||
import (
|
||||
"Wavelet/OpenFlare/plugins/server/admin"
|
||||
"Wavelet/OpenFlare/plugins/server/oauth"
|
||||
)
|
||||
import "Wavelet/core/contracts"
|
||||
|
||||
// AdminMiddlewares returns Wavelet-standard middlewares for OpenFlare console routes.
|
||||
// OpenFlare no longer distinguishes Admin vs Root tiers; all management endpoints share
|
||||
// the same gate: user.IsAdmin for session users, token_admin for Access Token callers.
|
||||
// the same gate: RequireAuth + RequireAdmin from the platform AuthService.
|
||||
//
|
||||
// 返回 []any 而非 []gin.HandlerFunc:内核 RouterExtension.Use 收 ...any,
|
||||
// 而 Go 不允许把 []T 直接展开成 ...any。
|
||||
func AdminMiddlewares() []any {
|
||||
return []any{oauth.LoginRequired(), admin.LoginAdminRequired()}
|
||||
func AdminMiddlewares(auth contracts.AuthService) []any {
|
||||
return []any{auth.RequireAuthMiddleware(), auth.RequireAdminMiddleware()}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@ import (
|
||||
|
||||
"Wavelet/OpenFlare/plugins/server/model"
|
||||
ofws "Wavelet/OpenFlare/plugins/server/openflare/websocket"
|
||||
"Wavelet/pkg/util"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -309,10 +308,6 @@ func isVersionNewer(current string, latest string) bool {
|
||||
return compareVersions(current, latest) < 0
|
||||
}
|
||||
|
||||
func compareVersions(local, remote string) int {
|
||||
return util.CompareVersions(local, remote)
|
||||
}
|
||||
|
||||
func fetchLatestGitHubRelease(ctx context.Context, repo string, channel releaseChannel) (*githubReleaseResponse, error) {
|
||||
switch normalizeReleaseChannel(string(channel)) {
|
||||
case releaseChannelPreview:
|
||||
|
||||
@@ -0,0 +1,227 @@
|
||||
// Copyright 2026 Arctel.net
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package node
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const gitDescribeMinIdentifiers = 2
|
||||
|
||||
type versionInfo struct {
|
||||
valid bool
|
||||
isDev bool
|
||||
numbers []int
|
||||
prerelease []string
|
||||
gitDescribeDistance int
|
||||
gitDescribeTail []string
|
||||
}
|
||||
|
||||
func parseVersionInfo(version string) versionInfo {
|
||||
normalized := strings.TrimSpace(strings.TrimPrefix(version, "v"))
|
||||
if normalized == "" || normalized == "dev" {
|
||||
return versionInfo{isDev: strings.EqualFold(normalized, "dev")}
|
||||
}
|
||||
base := normalized
|
||||
prerelease := ""
|
||||
if separator := strings.IndexRune(normalized, '-'); separator >= 0 {
|
||||
base = normalized[:separator]
|
||||
prerelease = normalized[separator+1:]
|
||||
}
|
||||
|
||||
segments := strings.Split(base, ".")
|
||||
parts := make([]int, 0, len(segments))
|
||||
for _, segment := range segments {
|
||||
segment = strings.TrimSpace(segment)
|
||||
if segment == "" {
|
||||
parts = append(parts, 0)
|
||||
continue
|
||||
}
|
||||
|
||||
numeric := strings.Builder{}
|
||||
for _, r := range segment {
|
||||
if r < '0' || r > '9' {
|
||||
break
|
||||
}
|
||||
numeric.WriteRune(r)
|
||||
}
|
||||
if numeric.Len() == 0 {
|
||||
parts = append(parts, 0)
|
||||
continue
|
||||
}
|
||||
value, err := strconv.Atoi(numeric.String())
|
||||
if err != nil {
|
||||
return versionInfo{}
|
||||
}
|
||||
parts = append(parts, value)
|
||||
}
|
||||
info := versionInfo{valid: len(parts) > 0, numbers: parts}
|
||||
if prerelease != "" {
|
||||
identifiers := splitPrereleaseIdentifiers(prerelease)
|
||||
if distance, tail, ok := parseGitDescribeIdentifiers(identifiers); ok {
|
||||
info.gitDescribeDistance = distance
|
||||
info.gitDescribeTail = tail
|
||||
} else {
|
||||
info.prerelease = identifiers
|
||||
}
|
||||
}
|
||||
return info
|
||||
}
|
||||
|
||||
func parseGitDescribeIdentifiers(identifiers []string) (int, []string, bool) {
|
||||
if len(identifiers) < gitDescribeMinIdentifiers {
|
||||
return 0, nil, false
|
||||
}
|
||||
distance, err := strconv.Atoi(strings.TrimSpace(identifiers[0]))
|
||||
if err != nil || distance <= 0 {
|
||||
return 0, nil, false
|
||||
}
|
||||
commitToken := strings.TrimSpace(identifiers[1])
|
||||
if commitToken == "" || !strings.HasPrefix(strings.ToLower(commitToken), "g") {
|
||||
return 0, nil, false
|
||||
}
|
||||
return distance, identifiers[1:], true
|
||||
}
|
||||
|
||||
func splitPrereleaseIdentifiers(value string) []string {
|
||||
parts := strings.FieldsFunc(strings.TrimSpace(value), func(r rune) bool {
|
||||
return r == '.' || r == '-'
|
||||
})
|
||||
filtered := make([]string, 0, len(parts))
|
||||
for _, part := range parts {
|
||||
part = strings.TrimSpace(part)
|
||||
if part != "" {
|
||||
filtered = append(filtered, part)
|
||||
}
|
||||
}
|
||||
return filtered
|
||||
}
|
||||
|
||||
func compareVersions(local, remote string) int {
|
||||
left := parseVersionInfo(local)
|
||||
right := parseVersionInfo(remote)
|
||||
if left.isDev {
|
||||
if right.valid {
|
||||
return -1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
if !left.valid || !right.valid {
|
||||
return 0
|
||||
}
|
||||
|
||||
if result := compareVersionNumbers(left, right); result != 0 {
|
||||
return result
|
||||
}
|
||||
if result := compareGitDescribeDistance(left, right); result != 0 {
|
||||
return result
|
||||
}
|
||||
if left.gitDescribeDistance > 0 || right.gitDescribeDistance > 0 {
|
||||
return compareGitDescribeTails(left, right)
|
||||
}
|
||||
return comparePrereleaseIdentifiers(left, right)
|
||||
}
|
||||
|
||||
func compareVersionNumbers(left, right versionInfo) int {
|
||||
maxLen := max(len(right.numbers), len(left.numbers))
|
||||
for index := range maxLen {
|
||||
leftValue := 0
|
||||
rightValue := 0
|
||||
if index < len(left.numbers) {
|
||||
leftValue = left.numbers[index]
|
||||
}
|
||||
if index < len(right.numbers) {
|
||||
rightValue = right.numbers[index]
|
||||
}
|
||||
if leftValue < rightValue {
|
||||
return -1
|
||||
}
|
||||
if leftValue > rightValue {
|
||||
return 1
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func compareGitDescribeDistance(left, right versionInfo) int {
|
||||
if left.gitDescribeDistance == right.gitDescribeDistance {
|
||||
return 0
|
||||
}
|
||||
if left.gitDescribeDistance < right.gitDescribeDistance {
|
||||
return -1
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
func compareGitDescribeTails(left, right versionInfo) int {
|
||||
maxLen := max(len(right.gitDescribeTail), len(left.gitDescribeTail))
|
||||
for index := range maxLen {
|
||||
if index >= len(left.gitDescribeTail) {
|
||||
return -1
|
||||
}
|
||||
if index >= len(right.gitDescribeTail) {
|
||||
return 1
|
||||
}
|
||||
if left.gitDescribeTail[index] < right.gitDescribeTail[index] {
|
||||
return -1
|
||||
}
|
||||
if left.gitDescribeTail[index] > right.gitDescribeTail[index] {
|
||||
return 1
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func comparePrereleaseIdentifiers(left, right versionInfo) int {
|
||||
if len(left.prerelease) == 0 && len(right.prerelease) == 0 {
|
||||
return 0
|
||||
}
|
||||
if len(left.prerelease) == 0 {
|
||||
return 1
|
||||
}
|
||||
if len(right.prerelease) == 0 {
|
||||
return -1
|
||||
}
|
||||
|
||||
maxLen := max(len(right.prerelease), len(left.prerelease))
|
||||
for index := range maxLen {
|
||||
if index >= len(left.prerelease) {
|
||||
return -1
|
||||
}
|
||||
if index >= len(right.prerelease) {
|
||||
return 1
|
||||
}
|
||||
if result := comparePrereleasePart(left.prerelease[index], right.prerelease[index]); result != 0 {
|
||||
return result
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func comparePrereleasePart(leftPart, rightPart string) int {
|
||||
leftNumber, leftErr := strconv.Atoi(leftPart)
|
||||
rightNumber, rightErr := strconv.Atoi(rightPart)
|
||||
switch {
|
||||
case leftErr == nil && rightErr == nil:
|
||||
if leftNumber < rightNumber {
|
||||
return -1
|
||||
}
|
||||
if leftNumber > rightNumber {
|
||||
return 1
|
||||
}
|
||||
case leftErr == nil:
|
||||
return -1
|
||||
case rightErr == nil:
|
||||
return 1
|
||||
default:
|
||||
if leftPart < rightPart {
|
||||
return -1
|
||||
}
|
||||
if leftPart > rightPart {
|
||||
return 1
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
@@ -1,16 +1,16 @@
|
||||
// Copyright 2026 Arctel.net
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package server 装载 OpenFlare 控制面插件:站点/区域、Cloudflare 接入、Pages 部署、
|
||||
// WAF、节点与回源管理、边缘协议接口以及根级默认路由,全部经 ctx.Router() 声明,
|
||||
// 由 driver_http 挂载到装配根提供的 gin engine 上。
|
||||
// Package server 装载 OpenFlare 控制面业务路由:站点/区域、Cloudflare 接入、Pages 部署、
|
||||
// WAF、节点与回源管理以及边缘协议接口。平台路径(user/admin/cap/health)由 Wavelet
|
||||
// 域插件注册,本插件只挂 OpenFlare 自己的业务。
|
||||
package server
|
||||
|
||||
import (
|
||||
"Wavelet/OpenFlare/plugins/server/infra/config"
|
||||
router_root "Wavelet/OpenFlare/plugins/server/router/root"
|
||||
v1 "Wavelet/OpenFlare/plugins/server/router/v1"
|
||||
ofrouter "Wavelet/OpenFlare/plugins/server/router/v1/openflare"
|
||||
"Wavelet/core"
|
||||
"Wavelet/core/contracts"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// Plugin 实现 core.Plugin,是 OpenFlare 控制面的装载入口。
|
||||
@@ -22,16 +22,24 @@ func New() *Plugin { return &Plugin{} }
|
||||
// Name 返回插件标识。
|
||||
func (p *Plugin) Name() string { return "server" }
|
||||
|
||||
// Apply 声明控制面 HTTP 路由树。
|
||||
//
|
||||
// 中间件(Recovery/CORS/session/otelgin/错误与日志)留在引擎层,由装配根的
|
||||
// router.BuildEngine 提供;内核暂无 engine 级中间件贡献点,见计划附录 A。
|
||||
// 任务、设置与迁移仍由 platform/bootstrap 显式装配,待后续迁入 Apply。
|
||||
func (p *Plugin) Apply(ctx *core.Context) error {
|
||||
root := ctx.Router()
|
||||
router_root.RegisterRootRoutes(root)
|
||||
// Inject waits for the same services as the Wavelet admin plugin so Apply runs
|
||||
// after platform admin routes exist and OpenFlare can replace /admin/update*.
|
||||
func (p *Plugin) Inject() []reflect.Type {
|
||||
return []reflect.Type{
|
||||
reflect.TypeFor[contracts.DBService](),
|
||||
reflect.TypeFor[contracts.CacheService](),
|
||||
reflect.TypeFor[contracts.UserService](),
|
||||
reflect.TypeFor[contracts.AuthService](),
|
||||
}
|
||||
}
|
||||
|
||||
api := root.Group(config.Config.App.APIPrefix)
|
||||
v1.RegisterV1Routes(api.Group("/v1"), api)
|
||||
// Apply 声明 OpenFlare 业务 HTTP 路由树。
|
||||
func (p *Plugin) Apply(ctx *core.Context) error {
|
||||
var auth contracts.AuthService
|
||||
if err := core.Using[contracts.AuthService](ctx, func(s contracts.AuthService) { auth = s }); err != nil {
|
||||
return err
|
||||
}
|
||||
ofrouter.RegisterV1Routes(ctx.Router().Group("/api/v1"), auth)
|
||||
ofrouter.RegisterRoutes(ctx.Router().Group("/api/v1"), auth)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -6,10 +6,13 @@
|
||||
// Agent/Relay/Tunnel protocol routes are mounted via RegisterRoutes under /api/v1.
|
||||
package openflare
|
||||
|
||||
import "Wavelet/core"
|
||||
import (
|
||||
"Wavelet/core"
|
||||
"Wavelet/core/contracts"
|
||||
)
|
||||
|
||||
// RegisterRoutes mounts Agent/Relay/Tunnel protocol routes under the /api/v1 group.
|
||||
func RegisterRoutes(apiV1Router core.RouterExtension) {
|
||||
func RegisterRoutes(apiV1Router core.RouterExtension, _ contracts.AuthService) {
|
||||
registerAgentRoutes(apiV1Router)
|
||||
registerRelayRoutes(apiV1Router)
|
||||
registerTunnelRoutes(apiV1Router)
|
||||
|
||||
@@ -7,11 +7,12 @@ import (
|
||||
"Wavelet/OpenFlare/plugins/server/openflare/apiutil"
|
||||
"Wavelet/OpenFlare/plugins/server/openflare/apply_log"
|
||||
"Wavelet/core"
|
||||
"Wavelet/core/contracts"
|
||||
)
|
||||
|
||||
func registerApplyLogRoutes(apiGroup core.RouterExtension) {
|
||||
func registerApplyLogRoutes(apiGroup core.RouterExtension, auth contracts.AuthService) {
|
||||
applyLogRoute := apiGroup.Group("/apply-logs")
|
||||
applyLogRoute.Use(apiutil.AdminMiddlewares()...)
|
||||
applyLogRoute.Use(apiutil.AdminMiddlewares(auth)...)
|
||||
{
|
||||
apiutil.RegisterCollection(applyLogRoute, "GET", apply_log.GetApplyLogs)
|
||||
applyLogRoute.POST("/cleanup", apply_log.CleanupApplyLogs)
|
||||
|
||||
@@ -7,11 +7,12 @@ import (
|
||||
"Wavelet/OpenFlare/plugins/server/openflare/apiutil"
|
||||
cf "Wavelet/OpenFlare/plugins/server/openflare/cloudflare"
|
||||
"Wavelet/core"
|
||||
"Wavelet/core/contracts"
|
||||
)
|
||||
|
||||
func registerCloudflareRoutes(apiGroup core.RouterExtension) {
|
||||
func registerCloudflareRoutes(apiGroup core.RouterExtension, auth contracts.AuthService) {
|
||||
route := apiGroup.Group("/cloudflare")
|
||||
route.Use(apiutil.AdminMiddlewares()...)
|
||||
route.Use(apiutil.AdminMiddlewares(auth)...)
|
||||
route.GET("/connection", cf.GetConnectionHandler)
|
||||
route.PUT("/connection", cf.SaveConnectionHandler)
|
||||
route.POST("/connection/verify", cf.VerifyConnectionHandler)
|
||||
|
||||
@@ -7,11 +7,12 @@ import (
|
||||
"Wavelet/OpenFlare/plugins/server/openflare/apiutil"
|
||||
"Wavelet/OpenFlare/plugins/server/openflare/config_version"
|
||||
"Wavelet/core"
|
||||
"Wavelet/core/contracts"
|
||||
)
|
||||
|
||||
func registerConfigVersionRoutes(apiGroup core.RouterExtension) {
|
||||
func registerConfigVersionRoutes(apiGroup core.RouterExtension, auth contracts.AuthService) {
|
||||
configVersionGroup := apiGroup.Group("/config-versions")
|
||||
configVersionGroup.Use(apiutil.AdminMiddlewares()...)
|
||||
configVersionGroup.Use(apiutil.AdminMiddlewares(auth)...)
|
||||
{
|
||||
apiutil.RegisterCollection(configVersionGroup, "GET", config_version.ListConfigVersionsHandler)
|
||||
configVersionGroup.GET("/active", config_version.GetActiveConfigVersionHandler)
|
||||
|
||||
@@ -7,11 +7,12 @@ import (
|
||||
"Wavelet/OpenFlare/plugins/server/openflare/apiutil"
|
||||
"Wavelet/OpenFlare/plugins/server/openflare/dashboard"
|
||||
"Wavelet/core"
|
||||
"Wavelet/core/contracts"
|
||||
)
|
||||
|
||||
func registerDashboardRoutes(apiGroup core.RouterExtension) {
|
||||
func registerDashboardRoutes(apiGroup core.RouterExtension, auth contracts.AuthService) {
|
||||
dashboardRoute := apiGroup.Group("/dashboard")
|
||||
dashboardRoute.Use(apiutil.AdminMiddlewares()...)
|
||||
dashboardRoute.Use(apiutil.AdminMiddlewares(auth)...)
|
||||
{
|
||||
dashboardRoute.GET("/overview", dashboard.GetOverviewHandler)
|
||||
}
|
||||
|
||||
@@ -7,11 +7,12 @@ import (
|
||||
"Wavelet/OpenFlare/plugins/server/openflare/apiutil"
|
||||
"Wavelet/OpenFlare/plugins/server/openflare/node"
|
||||
"Wavelet/core"
|
||||
"Wavelet/core/contracts"
|
||||
)
|
||||
|
||||
func registerNodeRoutes(apiGroup core.RouterExtension) {
|
||||
func registerNodeRoutes(apiGroup core.RouterExtension, auth contracts.AuthService) {
|
||||
nodeRoute := apiGroup.Group("/nodes")
|
||||
nodeRoute.Use(apiutil.AdminMiddlewares()...)
|
||||
nodeRoute.Use(apiutil.AdminMiddlewares(auth)...)
|
||||
{
|
||||
nodeRoute.GET("/bootstrap-token", node.GetBootstrapTokenHandler)
|
||||
nodeRoute.POST("/bootstrap-token/rotate", node.RotateBootstrapTokenHandler)
|
||||
|
||||
@@ -7,11 +7,12 @@ import (
|
||||
"Wavelet/OpenFlare/plugins/server/openflare/apiutil"
|
||||
"Wavelet/OpenFlare/plugins/server/openflare/observability"
|
||||
"Wavelet/core"
|
||||
"Wavelet/core/contracts"
|
||||
)
|
||||
|
||||
func registerObservabilityRoutes(apiGroup core.RouterExtension) {
|
||||
func registerObservabilityRoutes(apiGroup core.RouterExtension, auth contracts.AuthService) {
|
||||
accessLogRoute := apiGroup.Group("/access-logs")
|
||||
accessLogRoute.Use(apiutil.AdminMiddlewares()...)
|
||||
accessLogRoute.Use(apiutil.AdminMiddlewares(auth)...)
|
||||
{
|
||||
apiutil.RegisterCollection(accessLogRoute, "GET", observability.GetAccessLogsHandler)
|
||||
accessLogRoute.GET("/overview", observability.GetAccessLogOverviewHandler)
|
||||
|
||||
@@ -7,13 +7,14 @@ import (
|
||||
"Wavelet/OpenFlare/plugins/server/openflare/apiutil"
|
||||
"Wavelet/OpenFlare/plugins/server/openflare/option"
|
||||
"Wavelet/core"
|
||||
"Wavelet/core/contracts"
|
||||
)
|
||||
|
||||
func registerOptionRoutes(apiGroup core.RouterExtension) {
|
||||
func registerOptionRoutes(apiGroup core.RouterExtension, auth contracts.AuthService) {
|
||||
apiGroup.GET("/status", option.GetStatusHandler)
|
||||
|
||||
optionRoute := apiGroup.Group("/option")
|
||||
optionRoute.Use(apiutil.AdminMiddlewares()...)
|
||||
optionRoute.Use(apiutil.AdminMiddlewares(auth)...)
|
||||
{
|
||||
apiutil.RegisterCollection(optionRoute, "GET", option.ListOptionsHandler)
|
||||
optionRoute.POST("/update", option.UpdateOptionHandler)
|
||||
@@ -22,7 +23,7 @@ func registerOptionRoutes(apiGroup core.RouterExtension) {
|
||||
}
|
||||
|
||||
uptimeKumaRoute := apiGroup.Group("/uptimekuma")
|
||||
uptimeKumaRoute.Use(apiutil.AdminMiddlewares()...)
|
||||
uptimeKumaRoute.Use(apiutil.AdminMiddlewares(auth)...)
|
||||
{
|
||||
uptimeKumaRoute.POST("/sync", option.SyncUptimeKumaHandler)
|
||||
}
|
||||
|
||||
@@ -7,11 +7,12 @@ import (
|
||||
"Wavelet/OpenFlare/plugins/server/openflare/apiutil"
|
||||
"Wavelet/OpenFlare/plugins/server/openflare/origin"
|
||||
"Wavelet/core"
|
||||
"Wavelet/core/contracts"
|
||||
)
|
||||
|
||||
func registerOriginRoutes(apiGroup core.RouterExtension) {
|
||||
func registerOriginRoutes(apiGroup core.RouterExtension, auth contracts.AuthService) {
|
||||
originRoute := apiGroup.Group("/origins")
|
||||
originRoute.Use(apiutil.AdminMiddlewares()...)
|
||||
originRoute.Use(apiutil.AdminMiddlewares(auth)...)
|
||||
{
|
||||
apiutil.RegisterCollection(originRoute, "GET", origin.GetOrigins)
|
||||
originRoute.GET("/:id", origin.GetOrigin)
|
||||
|
||||
@@ -7,11 +7,12 @@ import (
|
||||
"Wavelet/OpenFlare/plugins/server/openflare/apiutil"
|
||||
"Wavelet/OpenFlare/plugins/server/openflare/pages"
|
||||
"Wavelet/core"
|
||||
"Wavelet/core/contracts"
|
||||
)
|
||||
|
||||
func registerPagesRoutes(apiGroup core.RouterExtension) {
|
||||
func registerPagesRoutes(apiGroup core.RouterExtension, auth contracts.AuthService) {
|
||||
pagesRoute := apiGroup.Group("/pages")
|
||||
pagesRoute.Use(apiutil.AdminMiddlewares()...)
|
||||
pagesRoute.Use(apiutil.AdminMiddlewares(auth)...)
|
||||
{
|
||||
apiutil.RegisterCollection(pagesRoute, "GET", pages.ListProjectsHandler)
|
||||
pagesRoute.GET("/:id", pages.GetProjectHandler)
|
||||
|
||||
@@ -7,11 +7,12 @@ import (
|
||||
"Wavelet/OpenFlare/plugins/server/openflare/apiutil"
|
||||
"Wavelet/OpenFlare/plugins/server/openflare/proxy_route"
|
||||
"Wavelet/core"
|
||||
"Wavelet/core/contracts"
|
||||
)
|
||||
|
||||
func registerProxyRouteRoutes(apiGroup core.RouterExtension) {
|
||||
func registerProxyRouteRoutes(apiGroup core.RouterExtension, auth contracts.AuthService) {
|
||||
proxyRouteGroup := apiGroup.Group("/proxy-routes")
|
||||
proxyRouteGroup.Use(apiutil.AdminMiddlewares()...)
|
||||
proxyRouteGroup.Use(apiutil.AdminMiddlewares(auth)...)
|
||||
{
|
||||
apiutil.RegisterCollection(proxyRouteGroup, "GET", proxy_route.GetProxyRoutes)
|
||||
proxyRouteGroup.GET("/:id", proxy_route.GetProxyRouteHandler)
|
||||
|
||||
@@ -7,11 +7,12 @@ import (
|
||||
"Wavelet/OpenFlare/plugins/server/openflare/apiutil"
|
||||
"Wavelet/OpenFlare/plugins/server/openflare/tls"
|
||||
"Wavelet/core"
|
||||
"Wavelet/core/contracts"
|
||||
)
|
||||
|
||||
func registerTLSRoutes(apiGroup core.RouterExtension) {
|
||||
func registerTLSRoutes(apiGroup core.RouterExtension, auth contracts.AuthService) {
|
||||
tlsCertificateRoute := apiGroup.Group("/tls-certificates")
|
||||
tlsCertificateRoute.Use(apiutil.AdminMiddlewares()...)
|
||||
tlsCertificateRoute.Use(apiutil.AdminMiddlewares(auth)...)
|
||||
{
|
||||
apiutil.RegisterCollection(tlsCertificateRoute, "GET", tls.GetCertificates)
|
||||
tlsCertificateRoute.GET("/:id", tls.GetCertificateDetail)
|
||||
@@ -27,13 +28,13 @@ func registerTLSRoutes(apiGroup core.RouterExtension) {
|
||||
}
|
||||
|
||||
acmeAccountRoute := apiGroup.Group("/acme-accounts")
|
||||
acmeAccountRoute.Use(apiutil.AdminMiddlewares()...)
|
||||
acmeAccountRoute.Use(apiutil.AdminMiddlewares(auth)...)
|
||||
{
|
||||
acmeAccountRoute.GET("/default", tls.GetDefaultAcmeAccountHandler)
|
||||
}
|
||||
|
||||
dnsAccountRoute := apiGroup.Group("/dns-accounts")
|
||||
dnsAccountRoute.Use(apiutil.AdminMiddlewares()...)
|
||||
dnsAccountRoute.Use(apiutil.AdminMiddlewares(auth)...)
|
||||
{
|
||||
apiutil.RegisterCollection(dnsAccountRoute, "GET", tls.GetDNSAccounts)
|
||||
apiutil.RegisterCollection(dnsAccountRoute, "POST", tls.CreateDNSAccountHandler)
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
// Copyright 2026 Arctel.net
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package openflare
|
||||
|
||||
import (
|
||||
"Wavelet/OpenFlare/plugins/server/admin/updater"
|
||||
"Wavelet/OpenFlare/plugins/server/openflare/apiutil"
|
||||
"Wavelet/core"
|
||||
"Wavelet/core/contracts"
|
||||
)
|
||||
|
||||
func registerUpdaterRoutes(apiV1Router core.RouterExtension, auth contracts.AuthService) {
|
||||
// Wavelet admin already registered these paths. Replace them so gin does
|
||||
// not panic on duplicate method+path at driver_http Start, and so the
|
||||
// OpenFlare updater implementation is the one that runs.
|
||||
_ = apiV1Router.Unregister("GET", "/admin/update")
|
||||
_ = apiV1Router.Unregister("POST", "/admin/update/apply")
|
||||
|
||||
adminRouter := apiV1Router.Group("/admin")
|
||||
adminRouter.Use(apiutil.AdminMiddlewares(auth)...)
|
||||
update := adminRouter.Group("/update")
|
||||
{
|
||||
update.GET("", updater.GetUpdateStatus)
|
||||
update.POST("/apply", updater.ApplyUpdate)
|
||||
}
|
||||
}
|
||||
@@ -7,11 +7,12 @@ import (
|
||||
"Wavelet/OpenFlare/plugins/server/openflare/apiutil"
|
||||
"Wavelet/OpenFlare/plugins/server/openflare/waf"
|
||||
"Wavelet/core"
|
||||
"Wavelet/core/contracts"
|
||||
)
|
||||
|
||||
func registerWAFRoutes(apiGroup core.RouterExtension) {
|
||||
func registerWAFRoutes(apiGroup core.RouterExtension, auth contracts.AuthService) {
|
||||
wafRoute := apiGroup.Group("/waf")
|
||||
wafRoute.Use(apiutil.AdminMiddlewares()...)
|
||||
wafRoute.Use(apiutil.AdminMiddlewares(auth)...)
|
||||
{
|
||||
wafRoute.GET("/ip-groups", waf.ListIPGroupsHandler)
|
||||
wafRoute.GET("/ip-groups/:id", waf.GetIPGroupHandler)
|
||||
|
||||
@@ -7,11 +7,12 @@ import (
|
||||
"Wavelet/OpenFlare/plugins/server/openflare/apiutil"
|
||||
"Wavelet/OpenFlare/plugins/server/openflare/zone"
|
||||
"Wavelet/core"
|
||||
"Wavelet/core/contracts"
|
||||
)
|
||||
|
||||
func registerZoneRoutes(apiGroup core.RouterExtension) {
|
||||
func registerZoneRoutes(apiGroup core.RouterExtension, auth contracts.AuthService) {
|
||||
zoneGroup := apiGroup.Group("/zones")
|
||||
zoneGroup.Use(apiutil.AdminMiddlewares()...)
|
||||
zoneGroup.Use(apiutil.AdminMiddlewares(auth)...)
|
||||
apiutil.RegisterCollection(zoneGroup, "GET", zone.ListHandler)
|
||||
apiutil.RegisterCollection(zoneGroup, "POST", zone.CreateHandler)
|
||||
zoneGroup.GET("/:id/overview", zone.GetOverviewHandler)
|
||||
|
||||
@@ -3,25 +3,30 @@
|
||||
|
||||
package openflare
|
||||
|
||||
import "Wavelet/core"
|
||||
import (
|
||||
"Wavelet/core"
|
||||
"Wavelet/core/contracts"
|
||||
)
|
||||
|
||||
// V1BasePath is the OpenFlare console API prefix under /api/v1.
|
||||
const V1BasePath = "/api/v1/d"
|
||||
|
||||
// RegisterV1Routes mounts OpenFlare management console APIs under /api/v1/d.
|
||||
func RegisterV1Routes(apiV1Router core.RouterExtension) {
|
||||
// RegisterV1Routes mounts OpenFlare management console APIs under /api/v1/d
|
||||
// and OpenFlare-owned admin updater routes under /api/v1/admin/update*.
|
||||
func RegisterV1Routes(apiV1Router core.RouterExtension, auth contracts.AuthService) {
|
||||
group := apiV1Router.Group("/d")
|
||||
registerOptionRoutes(group)
|
||||
registerOriginRoutes(group)
|
||||
registerApplyLogRoutes(group)
|
||||
registerProxyRouteRoutes(group)
|
||||
registerNodeRoutes(group)
|
||||
registerWAFRoutes(group)
|
||||
registerTLSRoutes(group)
|
||||
registerCloudflareRoutes(group)
|
||||
registerZoneRoutes(group)
|
||||
registerConfigVersionRoutes(group)
|
||||
registerPagesRoutes(group)
|
||||
registerDashboardRoutes(group)
|
||||
registerObservabilityRoutes(group)
|
||||
registerOptionRoutes(group, auth)
|
||||
registerOriginRoutes(group, auth)
|
||||
registerApplyLogRoutes(group, auth)
|
||||
registerProxyRouteRoutes(group, auth)
|
||||
registerNodeRoutes(group, auth)
|
||||
registerWAFRoutes(group, auth)
|
||||
registerTLSRoutes(group, auth)
|
||||
registerCloudflareRoutes(group, auth)
|
||||
registerZoneRoutes(group, auth)
|
||||
registerConfigVersionRoutes(group, auth)
|
||||
registerPagesRoutes(group, auth)
|
||||
registerDashboardRoutes(group, auth)
|
||||
registerObservabilityRoutes(group, auth)
|
||||
registerUpdaterRoutes(apiV1Router, auth)
|
||||
}
|
||||
|
||||
@@ -7,20 +7,13 @@ package v1
|
||||
import (
|
||||
ofrouter "Wavelet/OpenFlare/plugins/server/router/v1/openflare"
|
||||
"Wavelet/core"
|
||||
"Wavelet/core/contracts"
|
||||
)
|
||||
|
||||
// RegisterV1Routes registers all routes under API V1.
|
||||
func RegisterV1Routes(apiV1Router core.RouterExtension, apiGroup core.RouterExtension) {
|
||||
// 1. User & Public routes (OAuth, User, Upload, CAPTCHA, Health, Config)
|
||||
RegisterUserRoutes(apiV1Router, apiGroup)
|
||||
|
||||
// 2. Admin routes
|
||||
RegisterAdminRoutes(apiV1Router)
|
||||
|
||||
// 3. OpenFlare management console APIs and Agent/Relay/Tunnel protocol routes
|
||||
ofrouter.RegisterV1Routes(apiV1Router)
|
||||
ofrouter.RegisterRoutes(apiV1Router)
|
||||
|
||||
// 4. Custom business routes (example only)
|
||||
// RegisterV1Routes registers OpenFlare business routes under API V1.
|
||||
// Platform user/admin/cap/health routes are owned by Wavelet domain plugins.
|
||||
func RegisterV1Routes(apiV1Router core.RouterExtension, auth contracts.AuthService) {
|
||||
ofrouter.RegisterV1Routes(apiV1Router, auth)
|
||||
ofrouter.RegisterRoutes(apiV1Router, auth)
|
||||
RegisterCustomRoutes()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
// Copyright 2026 Arctel.net
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package stamp records pre-Cordis schema versions into w_schema_versions.
|
||||
package stamp
|
||||
|
||||
import "Wavelet/core"
|
||||
|
||||
// Legacy is the pre-Cordis schema stamp hook. Task 14 fills the body; until then
|
||||
// it is a no-op so plugin migrations can proceed on a fresh database.
|
||||
func Legacy(*core.Context) error {
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user