mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-10-02 14:56:38 +08:00
refactor(plugins): restructure admin and message_gateway into standard layered sub-packages
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
// Copyright 2026 Arctel.net
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package driver_http
|
||||
|
||||
import (
|
||||
"io"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
const indexFile = "index.html"
|
||||
|
||||
// serverOwnedPrefixes are backend-owned namespaces. A miss there must keep Gin's default
|
||||
// 404 instead of silently returning the frontend shell, which would mask broken API links.
|
||||
var serverOwnedPrefixes = []string{"/api/", "/f/"}
|
||||
|
||||
// registerFrontend mounts assets as the NoRoute fallback so client-side routes resolve.
|
||||
// It is a no-op when assets is nil, i.e. the binary was built without the embed_frontend tag.
|
||||
func registerFrontend(engine *gin.Engine, assets fs.FS) {
|
||||
if assets == nil {
|
||||
return
|
||||
}
|
||||
|
||||
engine.NoRoute(func(c *gin.Context) {
|
||||
if isServerOwned(c.Request.URL.Path) {
|
||||
return
|
||||
}
|
||||
|
||||
if c.Request.Method != http.MethodGet && c.Request.Method != http.MethodHead {
|
||||
c.JSON(http.StatusMethodNotAllowed, gin.H{"error_msg": "Method not allowed"})
|
||||
return
|
||||
}
|
||||
|
||||
for _, candidate := range assetCandidates(c.Request.URL.Path) {
|
||||
if serveAsset(c, assets, candidate) {
|
||||
return
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func isServerOwned(urlPath string) bool {
|
||||
for _, prefix := range serverOwnedPrefixes {
|
||||
if strings.HasPrefix(urlPath, prefix) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// assetCandidates maps a request path onto the static export layout: exact file,
|
||||
// Next.js clean-URL siblings, then the single-page-app shell.
|
||||
func assetCandidates(urlPath string) []string {
|
||||
clean := strings.TrimPrefix(path.Join("/", urlPath), "/")
|
||||
if clean == "" || clean == "." {
|
||||
return []string{indexFile}
|
||||
}
|
||||
|
||||
candidates := []string{clean}
|
||||
if !strings.Contains(clean, ".") {
|
||||
candidates = append(candidates, clean+".html", path.Join(clean, indexFile))
|
||||
}
|
||||
|
||||
return append(candidates, indexFile)
|
||||
}
|
||||
|
||||
// serveAsset writes name when it exists as a regular file, reporting whether it served.
|
||||
func serveAsset(c *gin.Context, assets fs.FS, name string) bool {
|
||||
file, err := assets.Open(name)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
defer func() { _ = file.Close() }()
|
||||
|
||||
info, err := file.Stat()
|
||||
if err != nil || info.IsDir() {
|
||||
return false
|
||||
}
|
||||
|
||||
seeker, ok := file.(io.ReadSeeker)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
http.ServeContent(c.Writer, c.Request, name, info.ModTime(), seeker)
|
||||
return true
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
//go:build !embed_frontend
|
||||
|
||||
// Copyright 2026 Arctel.net
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package driver_http
|
||||
|
||||
import "io/fs"
|
||||
|
||||
// frontendAssets returns nil: this binary was built without the embedded frontend bundle,
|
||||
// so unmatched routes keep Gin's default 404 and the frontend is served separately.
|
||||
func frontendAssets() fs.FS { return nil }
|
||||
@@ -0,0 +1,24 @@
|
||||
//go:build embed_frontend
|
||||
|
||||
// Copyright 2026 Arctel.net
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package driver_http
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"io/fs"
|
||||
)
|
||||
|
||||
//go:embed all:dist
|
||||
var frontendFS embed.FS
|
||||
|
||||
// frontendAssets returns the exported Next.js bundle shipped inside this binary.
|
||||
func frontendAssets() fs.FS {
|
||||
sub, err := fs.Sub(frontendFS, "dist")
|
||||
if err != nil {
|
||||
panic("driver_http: embedded frontend bundle unavailable: " + err.Error())
|
||||
}
|
||||
|
||||
return sub
|
||||
}
|
||||
@@ -162,6 +162,8 @@ func (p *Plugin) Start(ctx context.Context) error {
|
||||
}
|
||||
}
|
||||
|
||||
registerFrontend(p.engine, frontendAssets())
|
||||
|
||||
p.server = &http.Server{
|
||||
Addr: p.addr,
|
||||
Handler: p.engine,
|
||||
|
||||
Reference in New Issue
Block a user