feat: add locally syncing and watchdog
This commit is contained in:
@@ -2,6 +2,8 @@ package database
|
||||
|
||||
import (
|
||||
"eden-server/internal/utility"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@@ -9,19 +11,11 @@ import (
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func watchdog(env utility.Environment, db *gorm.DB) {
|
||||
slog.Info("performing the watchdog cycle")
|
||||
|
||||
func filesystemGather(env utility.Environment) (map[string]struct{}, error) {
|
||||
fsFiles, err := os.ReadDir(env.ContentDirectory)
|
||||
if err != nil {
|
||||
slog.Error("failed to read the content directory on the filesystem", "error", err)
|
||||
return
|
||||
}
|
||||
|
||||
dbFiles, err := GetFiles(db)
|
||||
if err != nil {
|
||||
slog.Error("failed to retrieve the files indexed from the database", "error", err)
|
||||
return
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// generate a set of filesystem contents
|
||||
@@ -32,41 +26,104 @@ func watchdog(env utility.Environment, db *gorm.DB) {
|
||||
fsSet[fullPath] = struct{}{}
|
||||
}
|
||||
|
||||
return fsSet, nil
|
||||
}
|
||||
|
||||
func databaseGather(db *gorm.DB) (map[string]File, error) {
|
||||
dbFiles, err := GetFiles(db)
|
||||
if err != nil {
|
||||
slog.Error("failed to retrieve the files indexed from the database", "error", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// generate a set of Database contents
|
||||
dbSet := make(map[string]File) // cool name for the files that are going to be deregistered from the database
|
||||
for _, f := range dbFiles {
|
||||
dbSet[f.FilePath] = f
|
||||
}
|
||||
|
||||
return dbSet, nil
|
||||
}
|
||||
|
||||
func watchdog(env utility.Environment, db *gorm.DB) {
|
||||
slog.Info("performing the watchdog cycle")
|
||||
|
||||
fsSet, err := filesystemGather(env)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
dbSet, err := databaseGather(db)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// FS -> DB
|
||||
// check for orphaned filesystem files
|
||||
var fsPurgeScroll []string
|
||||
var fsOrphans []string
|
||||
for path := range fsSet {
|
||||
if _, exists := dbSet[path]; !exists {
|
||||
fsPurgeScroll = append(fsPurgeScroll, path)
|
||||
fsOrphans = append(fsOrphans, path)
|
||||
}
|
||||
}
|
||||
|
||||
if len(fsOrphans) > 0 {
|
||||
slog.Info("filesystem orphans detected, engaging flow")
|
||||
//filepath is stored in the slice, the filename or file object, see above
|
||||
|
||||
for _, fp := range fsOrphans {
|
||||
// this switch is guarded by the environment.go its check making sure its one of the three
|
||||
// the following logic is used to actually perform the sync modes, removal, enrollment or ignore
|
||||
switch env.WatchdogSyncMode {
|
||||
case "sync":
|
||||
readerStream, err := os.Open(fp)
|
||||
if err != nil {
|
||||
|
||||
}
|
||||
defer readerStream.Close()
|
||||
|
||||
fileData, err := BuildFileRecord(readerStream, filepath.Base(fp), env.ContentDirectory)
|
||||
if err != nil {
|
||||
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)
|
||||
} else {
|
||||
slog.Error("failed to insert filedata to the database", "error", err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := os.Rename(fp, fileData.FilePath); err != nil {
|
||||
slog.Error("failed to move the locally inserted file", "error", err)
|
||||
}
|
||||
|
||||
case "strict":
|
||||
err := utility.RemoveFile(fp)
|
||||
if err != nil {
|
||||
slog.Warn("failed to remove local file from the filesystem", "error", err)
|
||||
}
|
||||
case "dry":
|
||||
slog.Debug("dry mode enabled, not purging", "filepath", fp)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// DB -> FS
|
||||
// check stale database records
|
||||
var dbPurgeScroll []File
|
||||
var dbdbOrphans []File
|
||||
for path, f := range dbSet {
|
||||
if _, exists := fsSet[path]; !exists {
|
||||
dbPurgeScroll = append(dbPurgeScroll, f)
|
||||
dbdbOrphans = append(dbdbOrphans, f)
|
||||
}
|
||||
}
|
||||
|
||||
if len(fsPurgeScroll) > 0 {
|
||||
slog.Info("filesystem purge scroll is populated, engaging purge")
|
||||
//filepath is stored in the slice, the filename or file object, see above
|
||||
for _, fp := range fsPurgeScroll {
|
||||
utility.RemoveFile(fp)
|
||||
}
|
||||
}
|
||||
|
||||
if len(dbPurgeScroll) > 0 {
|
||||
slog.Info("database purge scroll is populated, engaging purge")
|
||||
for _, f := range dbPurgeScroll {
|
||||
if len(dbdbOrphans) > 0 {
|
||||
slog.Info("database orphans detected, engaging flow")
|
||||
for _, f := range dbdbOrphans {
|
||||
DeregisterFile(db, f)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user