mirror of
https://github.com/fankes/beszel.git
synced 2025-10-20 02:09:28 +08:00
Refactor hub initialization and error handling
This commit is contained in:
@@ -5,6 +5,7 @@ import (
|
|||||||
"beszel/internal/hub"
|
"beszel/internal/hub"
|
||||||
_ "beszel/migrations"
|
_ "beszel/migrations"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
@@ -27,8 +28,9 @@ func main() {
|
|||||||
|
|
||||||
baseApp := getBaseApp()
|
baseApp := getBaseApp()
|
||||||
h := hub.NewHub(baseApp)
|
h := hub.NewHub(baseApp)
|
||||||
h.BootstrapHub()
|
if err := h.StartHub(); err != nil {
|
||||||
h.Start()
|
log.Fatal(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// getBaseApp creates a new PocketBase app with the default config
|
// getBaseApp creates a new PocketBase app with the default config
|
||||||
|
@@ -6,7 +6,6 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/pocketbase/dbx"
|
"github.com/pocketbase/dbx"
|
||||||
"github.com/pocketbase/pocketbase/apis"
|
"github.com/pocketbase/pocketbase/apis"
|
||||||
@@ -27,7 +26,8 @@ type SystemConfig struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Syncs systems with the config.yml file
|
// Syncs systems with the config.yml file
|
||||||
func (h *Hub) syncSystemsWithConfig() error {
|
func syncSystemsWithConfig(e *core.ServeEvent) error {
|
||||||
|
h := e.App
|
||||||
configPath := filepath.Join(h.DataDir(), "config.yml")
|
configPath := filepath.Join(h.DataDir(), "config.yml")
|
||||||
configData, err := os.ReadFile(configPath)
|
configData, err := os.ReadFile(configPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -89,16 +89,16 @@ func (h *Hub) syncSystemsWithConfig() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a map of existing systems for easy lookup
|
// Create a map of existing systems
|
||||||
existingSystemsMap := make(map[string]*core.Record)
|
existingSystemsMap := make(map[string]*core.Record)
|
||||||
for _, system := range existingSystems {
|
for _, system := range existingSystems {
|
||||||
key := system.GetString("host") + ":" + system.GetString("port")
|
key := system.GetString("name") + system.GetString("host") + system.GetString("port")
|
||||||
existingSystemsMap[key] = system
|
existingSystemsMap[key] = system
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process systems from config
|
// Process systems from config
|
||||||
for _, sysConfig := range config.Systems {
|
for _, sysConfig := range config.Systems {
|
||||||
key := sysConfig.Host + ":" + strconv.Itoa(int(sysConfig.Port))
|
key := sysConfig.Name + sysConfig.Host + cast.ToString(sysConfig.Port)
|
||||||
if existingSystem, ok := existingSystemsMap[key]; ok {
|
if existingSystem, ok := existingSystemsMap[key]; ok {
|
||||||
// Update existing system
|
// Update existing system
|
||||||
existingSystem.Set("name", sysConfig.Name)
|
existingSystem.Set("name", sysConfig.Name)
|
||||||
|
@@ -10,7 +10,6 @@ import (
|
|||||||
"beszel/site"
|
"beszel/site"
|
||||||
"crypto/ed25519"
|
"crypto/ed25519"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
"fmt"
|
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httputil"
|
"net/http/httputil"
|
||||||
@@ -56,42 +55,56 @@ func GetEnv(key string) (value string, exists bool) {
|
|||||||
return os.LookupEnv(key)
|
return os.LookupEnv(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Hub) BootstrapHub() (*Hub, error) {
|
func (h *Hub) StartHub() error {
|
||||||
if !h.App.IsBootstrapped() {
|
|
||||||
err := h.App.Bootstrap()
|
h.App.OnServe().BindFunc(func(e *core.ServeEvent) error {
|
||||||
if err != nil {
|
// initialize settings / collections
|
||||||
return nil, err
|
if err := h.initialize(e); err != nil {
|
||||||
}
|
return err
|
||||||
}
|
}
|
||||||
|
// sync systems with config
|
||||||
|
if err := syncSystemsWithConfig(e); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// register api routes
|
||||||
|
if err := h.registerApiRoutes(e); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// register cron jobs
|
||||||
|
if err := h.registerCronJobs(e); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// start server
|
||||||
|
if err := h.startServer(e); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// start system updates
|
||||||
|
if err := h.sm.Initialize(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return e.Next()
|
||||||
|
})
|
||||||
|
|
||||||
// serve web ui
|
|
||||||
h.OnServe().BindFunc(h.startServer)
|
|
||||||
// set up scheduled jobs
|
|
||||||
h.OnServe().BindFunc(h.registerCronJobs)
|
|
||||||
// custom api routes
|
|
||||||
h.OnServe().BindFunc(h.registerApiRoutes)
|
|
||||||
// TODO: move to users package
|
// TODO: move to users package
|
||||||
// handle default values for user / user_settings creation
|
// handle default values for user / user_settings creation
|
||||||
h.OnRecordCreate("users").BindFunc(h.um.InitializeUserRole)
|
h.App.OnRecordCreate("users").BindFunc(h.um.InitializeUserRole)
|
||||||
h.OnRecordCreate("user_settings").BindFunc(h.um.InitializeUserSettings)
|
h.App.OnRecordCreate("user_settings").BindFunc(h.um.InitializeUserSettings)
|
||||||
|
|
||||||
// sync systems with config
|
if pb, ok := h.App.(*pocketbase.PocketBase); ok {
|
||||||
h.syncSystemsWithConfig()
|
// log.Println("Starting pocketbase")
|
||||||
// start system updates
|
err := pb.Start()
|
||||||
h.sm.Initialize()
|
if err != nil {
|
||||||
|
return err
|
||||||
// initial setup
|
}
|
||||||
if err := h.initialize(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return h, nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// initialize sets up initial configuration (collections, settings, etc.)
|
// initialize sets up initial configuration (collections, settings, etc.)
|
||||||
func (h *Hub) initialize() error {
|
func (h *Hub) initialize(e *core.ServeEvent) error {
|
||||||
// set general settings
|
// set general settings
|
||||||
settings := h.Settings()
|
settings := e.App.Settings()
|
||||||
// batch requests (for global alerts)
|
// batch requests (for global alerts)
|
||||||
settings.Batch.Enabled = true
|
settings.Batch.Enabled = true
|
||||||
// set URL if BASE_URL env is set
|
// set URL if BASE_URL env is set
|
||||||
@@ -99,7 +112,7 @@ func (h *Hub) initialize() error {
|
|||||||
settings.Meta.AppURL = h.appURL
|
settings.Meta.AppURL = h.appURL
|
||||||
}
|
}
|
||||||
// set auth settings
|
// set auth settings
|
||||||
usersCollection, err := h.FindCollectionByNameOrId("users")
|
usersCollection, err := e.App.FindCollectionByNameOrId("users")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -118,11 +131,11 @@ func (h *Hub) initialize() error {
|
|||||||
} else {
|
} else {
|
||||||
usersCollection.CreateRule = nil
|
usersCollection.CreateRule = nil
|
||||||
}
|
}
|
||||||
if err := h.Save(usersCollection); err != nil {
|
if err := e.App.Save(usersCollection); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// allow all users to access systems if SHARE_ALL_SYSTEMS is set
|
// allow all users to access systems if SHARE_ALL_SYSTEMS is set
|
||||||
systemsCollection, err := h.FindCachedCollectionByNameOrId("systems")
|
systemsCollection, err := e.App.FindCachedCollectionByNameOrId("systems")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -137,21 +150,15 @@ func (h *Hub) initialize() error {
|
|||||||
systemsCollection.ViewRule = &systemsReadRule
|
systemsCollection.ViewRule = &systemsReadRule
|
||||||
systemsCollection.UpdateRule = &updateDeleteRule
|
systemsCollection.UpdateRule = &updateDeleteRule
|
||||||
systemsCollection.DeleteRule = &updateDeleteRule
|
systemsCollection.DeleteRule = &updateDeleteRule
|
||||||
if err := h.Save(systemsCollection); err != nil {
|
if err := e.App.Save(systemsCollection); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start starts the hub application / server
|
// startServer starts the server for the Beszel (not PocketBase)
|
||||||
func (h *Hub) Start() error {
|
|
||||||
if pb, ok := h.App.(*pocketbase.PocketBase); ok {
|
|
||||||
return pb.Start()
|
|
||||||
}
|
|
||||||
return fmt.Errorf("unable to start: App is not *pocketbase.PocketBase")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Hub) startServer(se *core.ServeEvent) error {
|
func (h *Hub) startServer(se *core.ServeEvent) error {
|
||||||
|
// TODO: exclude dev server from production binary
|
||||||
switch h.IsDev() {
|
switch h.IsDev() {
|
||||||
case true:
|
case true:
|
||||||
proxy := httputil.NewSingleHostReverseProxy(&url.URL{
|
proxy := httputil.NewSingleHostReverseProxy(&url.URL{
|
||||||
@@ -194,16 +201,16 @@ func (h *Hub) startServer(se *core.ServeEvent) error {
|
|||||||
return e.HTML(http.StatusOK, indexContent)
|
return e.HTML(http.StatusOK, indexContent)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return se.Next()
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// registerCronJobs sets up all scheduled tasks
|
// registerCronJobs sets up scheduled tasks
|
||||||
func (h *Hub) registerCronJobs(se *core.ServeEvent) error {
|
func (h *Hub) registerCronJobs(_ *core.ServeEvent) error {
|
||||||
// delete old records once every hour
|
// delete old records once every hour
|
||||||
h.Cron().MustAdd("delete old records", "8 * * * *", h.rm.DeleteOldRecords)
|
h.Cron().MustAdd("delete old records", "8 * * * *", h.rm.DeleteOldRecords)
|
||||||
// create longer records every 10 minutes
|
// create longer records every 10 minutes
|
||||||
h.Cron().MustAdd("create longer records", "*/10 * * * *", h.rm.CreateLongerRecords)
|
h.Cron().MustAdd("create longer records", "*/10 * * * *", h.rm.CreateLongerRecords)
|
||||||
return se.Next()
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// custom api routes
|
// custom api routes
|
||||||
@@ -229,7 +236,7 @@ func (h *Hub) registerApiRoutes(se *core.ServeEvent) error {
|
|||||||
if totalUsers, _ := h.CountRecords("users"); totalUsers == 0 {
|
if totalUsers, _ := h.CountRecords("users"); totalUsers == 0 {
|
||||||
se.Router.POST("/api/beszel/create-user", h.um.CreateFirstUser)
|
se.Router.POST("/api/beszel/create-user", h.um.CreateFirstUser)
|
||||||
}
|
}
|
||||||
return se.Next()
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// generates key pair if it doesn't exist and returns private key bytes
|
// generates key pair if it doesn't exist and returns private key bytes
|
||||||
|
Reference in New Issue
Block a user