From fa832bd1e0acee26f5fa8885892611415875e94d6fa539700640f0e5722c619e Mon Sep 17 00:00:00 2001 From: DaanSelen Date: Wed, 22 Apr 2026 16:29:07 +0200 Subject: [PATCH] feat: make watchdog itself configurable --- cmd/server/main.go | 16 +++++++++++----- deployments/debian/control | 2 +- go.mod | 4 ++-- internal/api/api.go | 2 +- internal/api/routes_api.go | 8 ++++++-- internal/api/routes_file.go | 6 +++--- internal/database/database.go | 9 +++++---- internal/database/define.go | 5 +++-- internal/database/functions.go | 8 ++++---- internal/database/watchdog.go | 9 ++++----- internal/utility/environment.go | 21 +++++++++++++++++++-- internal/utility/hash.go | 22 ---------------------- 12 files changed, 59 insertions(+), 53 deletions(-) diff --git a/cmd/server/main.go b/cmd/server/main.go index 6c6cce7..8a60dd6 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -1,10 +1,10 @@ package main import ( - "eden-server/internal/api" - "eden-server/internal/database" - "eden-server/internal/utility" "log/slog" + "orbits-server/internal/api" + "orbits-server/internal/database" + "orbits-server/internal/utility" "os" ) @@ -34,8 +34,14 @@ func main() { slog.Error("failed to initiate a database connection", "error", err) os.Exit(1) } - slog.Info("kicking off database watchdog", "watch_interval", env.WatchdogInterval) - database.KickoffDatabaseWatchdog(env, db) + + // kick off the watchdog depending on the environment variables + if env.WatchdogEnabled { + slog.Info("kicking off database watchdog", "watchdog_interval", env.WatchdogInterval) + database.KickoffDatabaseWatchdog(env, db) + } else { + slog.Info("skipping database watchdog", "watchdog_enabled", env.WatchdogEnabled) + } // TO DO make gin log as json // get ready to kick off the http api with Vue frontend diff --git a/deployments/debian/control b/deployments/debian/control index 4f9ba24..d76994c 100644 --- a/deployments/debian/control +++ b/deployments/debian/control @@ -1,4 +1,4 @@ -Package: eden-server +Package: orbits-server Version: 0.0.1 Section: base Priority: optional diff --git a/go.mod b/go.mod index dd22d5e..fba322a 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ -module eden-server +module orbits-server -go 1.25.0 +go 1.26.0 require ( github.com/gin-gonic/gin v1.12.0 diff --git a/internal/api/api.go b/internal/api/api.go index cf0da38..1c5bb7b 100644 --- a/internal/api/api.go +++ b/internal/api/api.go @@ -1,9 +1,9 @@ package api import ( - "eden-server/internal/utility" "fmt" "log/slog" + "orbits-server/internal/utility" "github.com/gin-gonic/gin" "gorm.io/gorm" diff --git a/internal/api/routes_api.go b/internal/api/routes_api.go index 978b4c0..4261efd 100644 --- a/internal/api/routes_api.go +++ b/internal/api/routes_api.go @@ -1,9 +1,9 @@ package api import ( - "eden-server/internal/database" "log/slog" "net/http" + "orbits-server/internal/database" "github.com/gin-gonic/gin" "gorm.io/gorm" @@ -12,7 +12,7 @@ import ( func spawnApiRoutes(api *gin.RouterGroup /* env runtime.Environment,*/, db *gorm.DB) { // prefix: api // Display the information on what is going on at the moment - api.GET("/status", func(c *gin.Context) { + api.GET("/command", func(c *gin.Context) { state, err := database.GetState(db) if err != nil { slog.Error("unable to determine state", "error", err) @@ -28,6 +28,10 @@ func spawnApiRoutes(api *gin.RouterGroup /* env runtime.Environment,*/, db *gorm }) }) + api.PATCH("/command", func(c *gin.Context) { + + }) + // define a route to check what is registered api.GET("/available", func(c *gin.Context) { files, err := database.GetFiles(db) diff --git a/internal/api/routes_file.go b/internal/api/routes_file.go index e746fe0..2df02a2 100644 --- a/internal/api/routes_file.go +++ b/internal/api/routes_file.go @@ -1,11 +1,11 @@ package api import ( - "eden-server/internal/database" - "eden-server/internal/utility" "errors" "log/slog" "net/http" + "orbits-server/internal/database" + "orbits-server/internal/utility" "path/filepath" "github.com/gin-gonic/gin" @@ -35,7 +35,7 @@ func spawnFileRoutes(file *gin.RouterGroup, env utility.Environment, db *gorm.DB readerStream, err := f.Open() if err != nil { - slog.Error("failed to open uploaded file in memory") + slog.Error("failed to a reader stream") } defer readerStream.Close() diff --git a/internal/database/database.go b/internal/database/database.go index 243c6a0..49e0e88 100644 --- a/internal/database/database.go +++ b/internal/database/database.go @@ -1,7 +1,7 @@ package database import ( - "eden-server/internal/utility" + "orbits-server/internal/utility" "path/filepath" "time" @@ -13,7 +13,7 @@ import ( //var watchdogStop = make(chan struct{}) func KickoffDatabase(workDir string) (*gorm.DB, error) { - dbLoc := filepath.Join(workDir, "garden.db") + dbLoc := filepath.Join(workDir, "station.db") db, err := gorm.Open(sqlite.Open(dbLoc), &gorm.Config{ Logger: logger.Discard, // disable gorm logging since its not slog (yet) TranslateError: true, @@ -24,7 +24,7 @@ func KickoffDatabase(workDir string) (*gorm.DB, error) { // try to use GORM automigrate if the schema changes if err := db.AutoMigrate( - &State{}, + &Command{}, &Device{}, &File{}, ); err != nil { @@ -32,8 +32,9 @@ func KickoffDatabase(workDir string) (*gorm.DB, error) { } // create the first row if it does not exist yet - if err := db.FirstOrCreate(&State{}, State{ + if err := db.FirstOrCreate(&Command{}, Command{ ID: 0, + State: "idle", MediaType: Unspecified, }).Error; err != nil { return nil, err diff --git a/internal/database/define.go b/internal/database/define.go index 965f69d..db85623 100644 --- a/internal/database/define.go +++ b/internal/database/define.go @@ -19,8 +19,9 @@ type Timestamps struct { ExpiresAt time.Time } -type State struct { - ID int `gorm:"primaryKey;not null;"` +type Command struct { + ID int `gorm:"primaryKey;not null;"` + State string // unspecified // video // presentation diff --git a/internal/database/functions.go b/internal/database/functions.go index 0e918ea..3bfad87 100644 --- a/internal/database/functions.go +++ b/internal/database/functions.go @@ -1,10 +1,10 @@ package database import ( - "eden-server/internal/utility" "fmt" "io" "log/slog" + "orbits-server/internal/utility" "path/filepath" "github.com/google/uuid" @@ -61,11 +61,11 @@ func BuildFileRecord(r io.Reader, origName string, contentDirectory string) (Fil return fData, nil } -func GetState(db *gorm.DB) (State, error) { - var state State +func GetState(db *gorm.DB) (Command, error) { + var state Command if err := db.First(&state).Error; err != nil { - return State{}, err + return Command{}, err } return state, nil diff --git a/internal/database/watchdog.go b/internal/database/watchdog.go index 12c2d73..8e93f3a 100644 --- a/internal/database/watchdog.go +++ b/internal/database/watchdog.go @@ -1,10 +1,9 @@ package database import ( - "eden-server/internal/utility" "errors" - "fmt" "log/slog" + "orbits-server/internal/utility" "os" "path/filepath" @@ -77,7 +76,7 @@ func watchdog(env utility.Environment, db *gorm.DB) { case "sync": readerStream, err := os.Open(fp) if err != nil { - + slog.Error("failed to a reader stream") } defer readerStream.Close() @@ -86,8 +85,6 @@ func watchdog(env utility.Environment, db *gorm.DB) { slog.Error("failed to enroll local file into the database", "error", err) } - fmt.Println(fileData) - if err := RegisterFile(db, fileData); err != nil { if errors.Is(err, gorm.ErrDuplicatedKey) { slog.Debug("discarding file since its a duplicate", "error", err) @@ -96,6 +93,8 @@ func watchdog(env utility.Environment, db *gorm.DB) { } } + // to fully finalize the enrollment process, we rename the locally inserted file to a unique filename + // this is to make all files comply, wether uploaded via the api or locally inserted with the filesystem if err := os.Rename(fp, fileData.FilePath); err != nil { slog.Error("failed to move the locally inserted file", "error", err) } diff --git a/internal/utility/environment.go b/internal/utility/environment.go index 50ff059..326907e 100644 --- a/internal/utility/environment.go +++ b/internal/utility/environment.go @@ -15,6 +15,7 @@ type Environment struct { ContentDirectory string Hostname string Port int + WatchdogEnabled bool WatchdogInterval int WatchdogSyncMode string } @@ -46,6 +47,15 @@ func safeIntGrab(key string, fallback int) int { return fallback } +func safeBoolGrab(key string, fallback bool) bool { + if v, ok := os.LookupEnv(key); ok { + if b, err := strconv.ParseBool(v); err == nil { + return b + } + } + return fallback +} + func safeSyncModeGrab(key, fallback string) string { if v, ok := os.LookupEnv(key); ok { if slices.Contains(validSyncModes, v) { @@ -66,12 +76,19 @@ func GrabEnvironment() Environment { fbContent := filepath.Join(fbBase, "content") return Environment{ - Version: safeStringGrab("VERSION", "0.0.1"), - Codename: safeStringGrab("CODENAME", "Magical Anomaly"), + // Basic server configuration + Version: safeStringGrab("VERSION", "0.0.1"), + Codename: safeStringGrab("CODENAME", "Magical Anomaly"), + + // GIN API configuration DataDirectory: safeStringGrab("DATA_DIR", fbBase), ContentDirectory: safeStringGrab("CONTENT_DIR", fbContent), Hostname: safeStringGrab("HOSTNAME", "0.0.0.0"), Port: safeIntGrab("PORT", 8080), + + // watchdog configuration + // watchdog is the integrity checker/steward + WatchdogEnabled: safeBoolGrab("WATCHDOG_ENABLED", true), WatchdogInterval: safeIntGrab("WATCHDOG_INTERVAL", 60), // sync: sync local files to the database, for example when you want to allow local inserting files which then get added to the database // strict: make the database leading, this is when you only allow API uploads to be registered, and remove orphaned filesystem files diff --git a/internal/utility/hash.go b/internal/utility/hash.go index 8aebc61..5b0d245 100644 --- a/internal/utility/hash.go +++ b/internal/utility/hash.go @@ -4,8 +4,6 @@ import ( "crypto/sha512" "encoding/hex" "io" - "mime/multipart" - "os" ) func HashReader(r io.Reader) (string, error) { @@ -19,23 +17,3 @@ func HashReader(r io.Reader) (string, error) { // alternatively return in base64 //return base64.StdEncoding.EncodeToString(h.Sum(nil)), nil } - -func HashUpload(fileHeader *multipart.FileHeader) (string, error) { - stream, err := fileHeader.Open() - if err != nil { - return "", err - } - defer stream.Close() - - return HashReader(stream) -} - -func HashFile(path string) (string, error) { - file, err := os.Open(path) - if err != nil { - return "", err - } - defer file.Close() - - return HashReader(file) -}