mirror of
https://github.com/henrygd/beszel.git
synced 2026-03-24 06:26:17 +01:00
ssr systems
This commit is contained in:
@@ -19,6 +19,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/pocketbase/dbx"
|
||||
"github.com/pocketbase/pocketbase"
|
||||
"github.com/pocketbase/pocketbase/apis"
|
||||
"github.com/pocketbase/pocketbase/core"
|
||||
@@ -112,6 +113,8 @@ func (h *Hub) initialize(e *core.ServeEvent) error {
|
||||
// set URL if BASE_URL env is set
|
||||
if h.appURL != "" {
|
||||
settings.Meta.AppURL = h.appURL
|
||||
} else {
|
||||
h.appURL = settings.Meta.AppURL
|
||||
}
|
||||
if err := e.App.Save(settings); err != nil {
|
||||
return err
|
||||
@@ -297,3 +300,30 @@ func (h *Hub) MakeLink(parts ...string) string {
|
||||
}
|
||||
return base
|
||||
}
|
||||
|
||||
type SystemInfo struct {
|
||||
Name string `json:"name"`
|
||||
Id string `json:"id"`
|
||||
Status string `json:"status"`
|
||||
Port uint16 `json:"port"`
|
||||
Host string `json:"host"`
|
||||
Info string `json:"info"`
|
||||
}
|
||||
|
||||
func (h *Hub) getUserSystemsFromRequest(req *http.Request) ([]SystemInfo, error) {
|
||||
systems := []SystemInfo{}
|
||||
token, err := req.Cookie("beszauth")
|
||||
if err != nil {
|
||||
return systems, err
|
||||
}
|
||||
if token.Value != "" {
|
||||
user, err := h.FindAuthRecordByToken(token.Value)
|
||||
if err != nil {
|
||||
return systems, err
|
||||
}
|
||||
h.DB().NewQuery("SELECT s.id, s.info, s.status, s.name, s.port, s.host FROM systems s JOIN json_each(s.users) AS je WHERE je.value = {:user_id}").Bind(dbx.Params{
|
||||
"user_id": user.Id,
|
||||
}).All(&systems)
|
||||
}
|
||||
return systems, err
|
||||
}
|
||||
|
||||
@@ -3,18 +3,96 @@
|
||||
package hub
|
||||
|
||||
import (
|
||||
"beszel"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/pocketbase/pocketbase/core"
|
||||
)
|
||||
|
||||
// responseModifier wraps an http.RoundTripper to modify HTML responses
|
||||
type responseModifier struct {
|
||||
transport http.RoundTripper
|
||||
hub *Hub
|
||||
}
|
||||
|
||||
// RoundTrip implements http.RoundTripper interface with response modification
|
||||
func (rm *responseModifier) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
resp, err := rm.transport.RoundTrip(req)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
|
||||
// Only modify HTML responses
|
||||
contentType := resp.Header.Get("Content-Type")
|
||||
if !strings.Contains(contentType, "text/html") {
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// Read the response body
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
resp.Body.Close()
|
||||
|
||||
// Modify the HTML content here
|
||||
modifiedBody := rm.modifyHTML(string(body), req)
|
||||
|
||||
// Create a new response with the modified body
|
||||
resp.Body = io.NopCloser(strings.NewReader(modifiedBody))
|
||||
resp.ContentLength = int64(len(modifiedBody))
|
||||
resp.Header.Set("Content-Length", fmt.Sprintf("%d", len(modifiedBody)))
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// modifyHTML applies modifications to HTML content
|
||||
func (rm *responseModifier) modifyHTML(html string, req *http.Request) string {
|
||||
parsedURL, err := url.Parse(rm.hub.appURL)
|
||||
if err != nil {
|
||||
return html
|
||||
}
|
||||
// fix base paths in html if using subpath
|
||||
basePath := strings.TrimSuffix(parsedURL.Path, "/") + "/"
|
||||
html = strings.ReplaceAll(html, "./", basePath)
|
||||
html = strings.Replace(html, "{{V}}", beszel.Version, 1)
|
||||
slog.Info("modifying HTML", "appURL", rm.hub.appURL)
|
||||
html = strings.Replace(html, "{{HUB_URL}}", rm.hub.appURL, 1)
|
||||
|
||||
systems, err := rm.hub.getUserSystemsFromRequest(req)
|
||||
if err != nil {
|
||||
return html
|
||||
}
|
||||
systemsJson, err := json.Marshal(systems)
|
||||
if err != nil {
|
||||
return html
|
||||
}
|
||||
html = strings.Replace(html, "'{SYSTEMS}'", string(systemsJson), 1)
|
||||
|
||||
return html
|
||||
}
|
||||
|
||||
// startServer sets up the development server for Beszel
|
||||
func (h *Hub) startServer(se *core.ServeEvent) error {
|
||||
slog.Info("starting server", "appURL", h.appURL)
|
||||
proxy := httputil.NewSingleHostReverseProxy(&url.URL{
|
||||
Scheme: "http",
|
||||
Host: "localhost:5173",
|
||||
})
|
||||
|
||||
// Set up custom transport with response modification
|
||||
proxy.Transport = &responseModifier{
|
||||
transport: http.DefaultTransport,
|
||||
hub: h,
|
||||
}
|
||||
|
||||
se.Router.GET("/{path...}", func(e *core.RequestEvent) error {
|
||||
proxy.ServeHTTP(e.Response, e.Request)
|
||||
return nil
|
||||
|
||||
@@ -5,7 +5,9 @@ package hub
|
||||
import (
|
||||
"beszel"
|
||||
"beszel/site"
|
||||
"encoding/json"
|
||||
"io/fs"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
@@ -24,9 +26,9 @@ func (h *Hub) startServer(se *core.ServeEvent) error {
|
||||
// fix base paths in html if using subpath
|
||||
basePath := strings.TrimSuffix(parsedURL.Path, "/") + "/"
|
||||
indexFile, _ := fs.ReadFile(site.DistDirFS, "index.html")
|
||||
indexContent := strings.ReplaceAll(string(indexFile), "./", basePath)
|
||||
indexContent = strings.Replace(indexContent, "{{V}}", beszel.Version, 1)
|
||||
indexContent = strings.Replace(indexContent, "{{HUB_URL}}", h.appURL, 1)
|
||||
html := strings.ReplaceAll(string(indexFile), "./", basePath)
|
||||
html = strings.Replace(html, "{{V}}", beszel.Version, 1)
|
||||
html = strings.Replace(html, "{{HUB_URL}}", h.appURL, 1)
|
||||
// set up static asset serving
|
||||
staticPaths := [2]string{"/static/", "/assets/"}
|
||||
serveStatic := apis.Static(site.DistDirFS, false)
|
||||
@@ -45,7 +47,16 @@ func (h *Hub) startServer(se *core.ServeEvent) error {
|
||||
e.Response.Header().Del("X-Frame-Options")
|
||||
e.Response.Header().Set("Content-Security-Policy", csp)
|
||||
}
|
||||
return e.HTML(http.StatusOK, indexContent)
|
||||
systems, err := h.getUserSystemsFromRequest(e.Request)
|
||||
if err != nil {
|
||||
slog.Error("error getting user systems", "error", err)
|
||||
}
|
||||
systemsJson, err := json.Marshal(systems)
|
||||
if err != nil {
|
||||
slog.Error("error marshalling user systems", "error", err)
|
||||
}
|
||||
html = strings.Replace(html, "'{SYSTEMS}'", string(systemsJson), 1)
|
||||
return e.HTML(http.StatusOK, html)
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user