fix things

This commit is contained in:
2025-08-18 19:38:42 +02:00
parent 97cd8f065f
commit b2425d310b
6 changed files with 82 additions and 154 deletions

View File

@@ -3,7 +3,6 @@ package api
import ( import (
"cloudsave/pkg/data" "cloudsave/pkg/data"
"cloudsave/pkg/repository" "cloudsave/pkg/repository"
"encoding/json"
"errors" "errors"
"fmt" "fmt"
"log/slog" "log/slog"
@@ -36,7 +35,7 @@ func NewServer(documentRoot string, srv *data.Service, creds map[string]string,
} }
router := chi.NewRouter() router := chi.NewRouter()
router.NotFound(func(writer http.ResponseWriter, request *http.Request) { router.NotFound(func(writer http.ResponseWriter, request *http.Request) {
notFound("This route does not exist", writer, request) notFound("id not found", writer, request)
}) })
router.MethodNotAllowed(func(writer http.ResponseWriter, request *http.Request) { router.MethodNotAllowed(func(writer http.ResponseWriter, request *http.Request) {
methodNotAllowed(writer, request) methodNotAllowed(writer, request)
@@ -81,43 +80,13 @@ func NewServer(documentRoot string, srv *data.Service, creds map[string]string,
} }
func (s HTTPServer) all(w http.ResponseWriter, r *http.Request) { func (s HTTPServer) all(w http.ResponseWriter, r *http.Request) {
path := filepath.Join(s.documentRoot, "data") datastore, err := s.Service.AllGames()
datastore := make([]repository.Metadata, 0) if err != nil {
slog.Error(err.Error())
if _, err := os.Stat(path); err != nil {
if errors.Is(err, os.ErrNotExist) {
ok(datastore, w, r)
return
}
fmt.Fprintln(os.Stderr, "failed to open datastore (", s.documentRoot, "):", err)
internalServerError(w, r) internalServerError(w, r)
return return
} }
ds, err := os.ReadDir(path)
if err != nil {
fmt.Fprintln(os.Stderr, "failed to open datastore (", s.documentRoot, "):", err)
internalServerError(w, r)
return
}
for _, d := range ds {
content, err := os.ReadFile(filepath.Join(path, d.Name(), "metadata.json"))
if err != nil {
slog.Error("error: failed to load metadata.json", "err", err)
continue
}
var m repository.Metadata
err = json.Unmarshal(content, &m)
if err != nil {
fmt.Fprintf(os.Stderr, "corrupted datastore: failed to parse %s/metadata.json: %s", d.Name(), err)
internalServerError(w, r)
}
datastore = append(datastore, m)
}
ok(datastore, w, r) ok(datastore, w, r)
} }
@@ -125,32 +94,19 @@ func (s HTTPServer) download(w http.ResponseWriter, r *http.Request) {
id := chi.URLParam(r, "id") id := chi.URLParam(r, "id")
path := filepath.Clean(filepath.Join(s.documentRoot, "data", id)) path := filepath.Clean(filepath.Join(s.documentRoot, "data", id))
sdir, err := os.Stat(path) fi, err := os.Stat(filepath.Join(path, "data.tar.gz"))
if err != nil { if err != nil {
notFound("id not found", w, r) notFound("id not found", w, r)
return return
} }
if !sdir.IsDir() { f, err := s.Service.Repository().ReadBlob(repository.NewGameIdentifier(id))
notFound("id not found", w, r)
return
}
path = filepath.Join(path, "data.tar.gz")
f, err := os.OpenFile(path, os.O_RDONLY, 0)
if err != nil { if err != nil {
notFound("id not found", w, r) slog.Error(err.Error())
return
}
defer f.Close()
// Get file info to set headers
fi, err := f.Stat()
if err != nil || fi.IsDir() {
internalServerError(w, r) internalServerError(w, r)
return return
} }
defer f.Close()
// Set headers // Set headers
w.Header().Set("Content-Disposition", "attachment; filename=\"data.tar.gz\"") w.Header().Set("Content-Disposition", "attachment; filename=\"data.tar.gz\"")
@@ -274,32 +230,19 @@ func (s HTTPServer) histDownload(w http.ResponseWriter, r *http.Request) {
uuid := chi.URLParam(r, "uuid") uuid := chi.URLParam(r, "uuid")
path := filepath.Clean(filepath.Join(s.documentRoot, "data", id, "hist", uuid)) path := filepath.Clean(filepath.Join(s.documentRoot, "data", id, "hist", uuid))
sdir, err := os.Stat(path) fi, err := os.Stat(filepath.Join(path, "data.tar.gz"))
if err != nil { if err != nil {
notFound("id not found", w, r) notFound("id not found", w, r)
return return
} }
if !sdir.IsDir() { f, err := s.Service.Repository().ReadBlob(repository.NewBackupIdentifier(id, uuid))
notFound("id not found", w, r)
return
}
path = filepath.Join(path, "data.tar.gz")
f, err := os.OpenFile(path, os.O_RDONLY, 0)
if err != nil { if err != nil {
notFound("id not found", w, r) slog.Error(err.Error())
return
}
defer f.Close()
// Get file info to set headers
fi, err := f.Stat()
if err != nil || fi.IsDir() {
internalServerError(w, r) internalServerError(w, r)
return return
} }
defer f.Close()
// Set headers // Set headers
w.Header().Set("Content-Disposition", "attachment; filename=\"data.tar.gz\"") w.Header().Set("Content-Disposition", "attachment; filename=\"data.tar.gz\"")
@@ -348,37 +291,16 @@ func (s HTTPServer) hash(w http.ResponseWriter, r *http.Request) {
func (s HTTPServer) metadata(w http.ResponseWriter, r *http.Request) { func (s HTTPServer) metadata(w http.ResponseWriter, r *http.Request) {
id := chi.URLParam(r, "id") id := chi.URLParam(r, "id")
path := filepath.Clean(filepath.Join(s.documentRoot, "data", id)) metadata, err := s.Service.One(id)
sdir, err := os.Stat(path)
if err != nil { if err != nil {
if errors.Is(err, repository.ErrNotFound) {
notFound("id not found", w, r) notFound("id not found", w, r)
return return
} }
slog.Error(err.Error())
if !sdir.IsDir() {
notFound("id not found", w, r)
return
}
path = filepath.Join(path, "metadata.json")
f, err := os.OpenFile(path, os.O_RDONLY, 0)
if err != nil {
notFound("id not found", w, r)
return
}
defer f.Close()
var metadata repository.Metadata
d := json.NewDecoder(f)
err = d.Decode(&metadata)
if err != nil {
fmt.Fprintln(os.Stderr, "error: an error occured while reading data:", err)
internalServerError(w, r) internalServerError(w, r)
return return
} }
ok(metadata, w, r) ok(metadata, w, r)
} }

View File

@@ -3,13 +3,13 @@ package api
import ( import (
"cloudsave/pkg/remote/obj" "cloudsave/pkg/remote/obj"
"encoding/json" "encoding/json"
"log" "log/slog"
"net/http" "net/http"
"time" "time"
) )
func internalServerError(w http.ResponseWriter, r *http.Request) { func internalServerError(w http.ResponseWriter, r *http.Request) {
e := obj.HTTPError{ payload := obj.HTTPError{
HTTPCore: obj.HTTPCore{ HTTPCore: obj.HTTPCore{
Status: http.StatusInternalServerError, Status: http.StatusInternalServerError,
Path: r.RequestURI, Path: r.RequestURI,
@@ -19,20 +19,16 @@ func internalServerError(w http.ResponseWriter, r *http.Request) {
Message: "The server encountered an unexpected condition that prevented it from fulfilling the request.", Message: "The server encountered an unexpected condition that prevented it from fulfilling the request.",
} }
payload, err := json.Marshal(e)
if err != nil {
log.Println(err)
}
w.Header().Add("Content-Type", "application/json") w.Header().Add("Content-Type", "application/json")
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusInternalServerError)
_, err = w.Write(payload) e := json.NewEncoder(w)
if err != nil { if err := e.Encode(payload); err != nil {
log.Println(err) slog.Error(err.Error())
} }
} }
func notFound(message string, w http.ResponseWriter, r *http.Request) { func notFound(message string, w http.ResponseWriter, r *http.Request) {
e := obj.HTTPError{ payload := obj.HTTPError{
HTTPCore: obj.HTTPCore{ HTTPCore: obj.HTTPCore{
Status: http.StatusNotFound, Status: http.StatusNotFound,
Path: r.RequestURI, Path: r.RequestURI,
@@ -42,20 +38,16 @@ func notFound(message string, w http.ResponseWriter, r *http.Request) {
Message: message, Message: message,
} }
payload, err := json.Marshal(e)
if err != nil {
log.Println(err)
}
w.Header().Add("Content-Type", "application/json") w.Header().Add("Content-Type", "application/json")
w.WriteHeader(http.StatusNotFound) w.WriteHeader(http.StatusNotFound)
_, err = w.Write(payload) e := json.NewEncoder(w)
if err != nil { if err := e.Encode(payload); err != nil {
log.Println(err) slog.Error(err.Error())
} }
} }
func methodNotAllowed(w http.ResponseWriter, r *http.Request) { func methodNotAllowed(w http.ResponseWriter, r *http.Request) {
e := obj.HTTPError{ payload := obj.HTTPError{
HTTPCore: obj.HTTPCore{ HTTPCore: obj.HTTPCore{
Status: http.StatusMethodNotAllowed, Status: http.StatusMethodNotAllowed,
Path: r.RequestURI, Path: r.RequestURI,
@@ -65,20 +57,16 @@ func methodNotAllowed(w http.ResponseWriter, r *http.Request) {
Message: "The server knows the request method, but the target resource doesn't support this method", Message: "The server knows the request method, but the target resource doesn't support this method",
} }
payload, err := json.Marshal(e)
if err != nil {
log.Println(err)
}
w.Header().Add("Content-Type", "application/json") w.Header().Add("Content-Type", "application/json")
w.WriteHeader(http.StatusMethodNotAllowed) w.WriteHeader(http.StatusMethodNotAllowed)
_, err = w.Write(payload) e := json.NewEncoder(w)
if err != nil { if err := e.Encode(payload); err != nil {
log.Println(err) slog.Error(err.Error())
} }
} }
func unauthorized(w http.ResponseWriter, r *http.Request) { func unauthorized(w http.ResponseWriter, r *http.Request) {
e := obj.HTTPError{ payload := obj.HTTPError{
HTTPCore: obj.HTTPCore{ HTTPCore: obj.HTTPCore{
Status: http.StatusUnauthorized, Status: http.StatusUnauthorized,
Path: r.RequestURI, Path: r.RequestURI,
@@ -88,21 +76,17 @@ func unauthorized(w http.ResponseWriter, r *http.Request) {
Message: "The request has not been completed because it lacks valid authentication credentials for the requested resource.", Message: "The request has not been completed because it lacks valid authentication credentials for the requested resource.",
} }
payload, err := json.Marshal(e)
if err != nil {
log.Println(err)
}
w.Header().Add("Content-Type", "application/json") w.Header().Add("Content-Type", "application/json")
w.Header().Add("WWW-Authenticate", "Custom realm=\"loginUserHandler via /api/login\"") w.Header().Add("WWW-Authenticate", "Custom realm=\"loginUserHandler via /api/login\"")
w.WriteHeader(http.StatusUnauthorized) w.WriteHeader(http.StatusUnauthorized)
_, err = w.Write(payload) e := json.NewEncoder(w)
if err != nil { if err := e.Encode(payload); err != nil {
log.Println(err) slog.Error(err.Error())
} }
} }
func ok(o interface{}, w http.ResponseWriter, r *http.Request) { func ok(o interface{}, w http.ResponseWriter, r *http.Request) {
e := obj.HTTPObject{ payload := obj.HTTPObject{
HTTPCore: obj.HTTPCore{ HTTPCore: obj.HTTPCore{
Status: http.StatusOK, Status: http.StatusOK,
Path: r.RequestURI, Path: r.RequestURI,
@@ -110,20 +94,15 @@ func ok(o interface{}, w http.ResponseWriter, r *http.Request) {
}, },
Data: o, Data: o,
} }
payload, err := json.Marshal(e)
if err != nil {
log.Println(err)
}
w.Header().Add("Content-Type", "application/json") w.Header().Add("Content-Type", "application/json")
_, err = w.Write(payload) e := json.NewEncoder(w)
if err != nil { if err := e.Encode(payload); err != nil {
log.Println(err) slog.Error(err.Error())
} }
} }
func badRequest(message string, w http.ResponseWriter, r *http.Request) { func badRequest(message string, w http.ResponseWriter, r *http.Request) {
e := obj.HTTPError{ payload := obj.HTTPError{
HTTPCore: obj.HTTPCore{ HTTPCore: obj.HTTPCore{
Status: http.StatusBadRequest, Status: http.StatusBadRequest,
Path: r.RequestURI, Path: r.RequestURI,
@@ -133,14 +112,10 @@ func badRequest(message string, w http.ResponseWriter, r *http.Request) {
Message: message, Message: message,
} }
payload, err := json.Marshal(e)
if err != nil {
log.Println(err)
}
w.Header().Add("Content-Type", "application/json") w.Header().Add("Content-Type", "application/json")
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
_, err = w.Write(payload) e := json.NewEncoder(w)
if err != nil { if err := e.Encode(payload); err != nil {
log.Println(err) slog.Error(err.Error())
} }
} }

View File

@@ -8,6 +8,7 @@ import (
"cloudsave/pkg/repository" "cloudsave/pkg/repository"
"flag" "flag"
"fmt" "fmt"
"log/slog"
"path/filepath" "path/filepath"
"runtime" "runtime"
"strconv" "strconv"
@@ -18,18 +19,27 @@ func run() {
var documentRoot string var documentRoot string
var port int var port int
var noCache bool var noCache, verbose bool
flag.StringVar(&documentRoot, "document-root", defaultDocumentRoot, "Define the path to the document root") flag.StringVar(&documentRoot, "document-root", defaultDocumentRoot, "Define the path to the document root")
flag.IntVar(&port, "port", 8080, "Define the port of the server") flag.IntVar(&port, "port", 8080, "Define the port of the server")
flag.BoolVar(&noCache, "no-cache", false, "Disable the cache") flag.BoolVar(&noCache, "no-cache", false, "Disable the cache")
flag.BoolVar(&verbose, "verbose", false, "Show more logs")
flag.Parse() flag.Parse()
if verbose {
slog.SetLogLoggerLevel(slog.LevelDebug)
}
slog.Info("loading .htpasswd")
h, err := htpasswd.Open(filepath.Join(documentRoot, ".htpasswd")) h, err := htpasswd.Open(filepath.Join(documentRoot, ".htpasswd"))
if err != nil { if err != nil {
fatal("failed to load .htpasswd: "+err.Error(), 1) fatal("failed to load .htpasswd: "+err.Error(), 1)
} }
slog.Info("users loaded: " + strconv.Itoa(len(h.Content())) + " user(s) loaded")
var repo repository.Repository var repo repository.Repository
if noCache { if !noCache {
slog.Info("loading eager repository...")
r, err := repository.NewEagerRepository(filepath.Join(documentRoot, "data")) r, err := repository.NewEagerRepository(filepath.Join(documentRoot, "data"))
if err != nil { if err != nil {
fatal("failed to load datastore: "+err.Error(), 1) fatal("failed to load datastore: "+err.Error(), 1)
@@ -39,17 +49,19 @@ func run() {
} }
repo = r repo = r
} else { } else {
slog.Info("loading lazy repository...")
repo, err = repository.NewLazyRepository(filepath.Join(documentRoot, "data")) repo, err = repository.NewLazyRepository(filepath.Join(documentRoot, "data"))
if err != nil { if err != nil {
fatal("failed to load datastore: "+err.Error(), 1) fatal("failed to load datastore: "+err.Error(), 1)
} }
} }
slog.Info("repository loaded")
s := data.NewService(repo) s := data.NewService(repo)
server := api.NewServer(documentRoot, s, h.Content(), port) server := api.NewServer(documentRoot, s, h.Content(), port)
fmt.Println("starting server at :" + strconv.Itoa(port)) fmt.Println("server started at :" + strconv.Itoa(port))
if err := server.Server.ListenAndServe(); err != nil { if err := server.Server.ListenAndServe(); err != nil {
fatal("failed to start server: "+err.Error(), 1) fatal("failed to start server: "+err.Error(), 1)
} }

View File

@@ -1,5 +1,5 @@
package constants package constants
const Version = "0.0.4a" const Version = "0.0.4b"
const ApiVersion = 1 const ApiVersion = 1

View File

@@ -268,8 +268,6 @@ func (l Service) PullBackup(gameID, backupID string, cli *client.Client) error {
return fmt.Errorf("failed to pull backup: %w", err) return fmt.Errorf("failed to pull backup: %w", err)
} }
return nil return nil
} }
@@ -372,6 +370,10 @@ func (l Service) ApplyBackup(gameID, backupID string) error {
return l.apply(filepath.Join(path, "data.tar.gz"), g.Path) return l.apply(filepath.Join(path, "data.tar.gz"), g.Path)
} }
func (l Service) Repository() repository.Repository {
return l.repo
}
func (l Service) apply(src, dst string) error { func (l Service) apply(src, dst string) error {
if err := os.RemoveAll(dst); err != nil { if err := os.RemoveAll(dst); err != nil {
return fmt.Errorf("failed to remove old save: %w", err) return fmt.Errorf("failed to remove old save: %w", err)

View File

@@ -6,6 +6,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"io" "io"
"log/slog"
"os" "os"
"path/filepath" "path/filepath"
"time" "time"
@@ -74,7 +75,7 @@ type (
Metadata(gameID GameIdentifier) (Metadata, error) Metadata(gameID GameIdentifier) (Metadata, error)
LastScan(gameID GameIdentifier) (time.Time, error) LastScan(gameID GameIdentifier) (time.Time, error)
ReadBlob(gameID Identifier) (io.Reader, error) ReadBlob(gameID Identifier) (io.ReadSeekCloser, error)
Backup(id BackupIdentifier) (Backup, error) Backup(id BackupIdentifier) (Backup, error)
Remote(id GameIdentifier) (*Remote, error) Remote(id GameIdentifier) (*Remote, error)
@@ -132,10 +133,16 @@ func NewLazyRepository(dataRootPath string) (*LazyRepository, error) {
} }
func (l *LazyRepository) Mkdir(id Identifier) error { func (l *LazyRepository) Mkdir(id Identifier) error {
return os.MkdirAll(l.DataPath(id), 0740) path := l.DataPath(id)
if _, err := os.Stat(path); errors.Is(err, os.ErrNotExist) {
slog.Debug("making directory", "path", path, "id", id, "perm", "0740")
return os.MkdirAll(path, 0740)
}
return nil
} }
func (l *LazyRepository) All() ([]string, error) { func (l *LazyRepository) All() ([]string, error) {
slog.Debug("loading all current data...")
dir, err := os.ReadDir(l.dataRoot) dir, err := os.ReadDir(l.dataRoot)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to open directory: %w", err) return nil, fmt.Errorf("failed to open directory: %w", err)
@@ -152,6 +159,7 @@ func (l *LazyRepository) All() ([]string, error) {
func (l *LazyRepository) AllHist(id GameIdentifier) ([]string, error) { func (l *LazyRepository) AllHist(id GameIdentifier) ([]string, error) {
path := l.DataPath(id) path := l.DataPath(id)
slog.Debug("loading hist data...", "id", id)
dir, err := os.ReadDir(filepath.Join(path, "hist")) dir, err := os.ReadDir(filepath.Join(path, "hist"))
if err != nil { if err != nil {
if errors.Is(err, os.ErrNotExist) { if errors.Is(err, os.ErrNotExist) {
@@ -171,6 +179,7 @@ func (l *LazyRepository) AllHist(id GameIdentifier) ([]string, error) {
func (l *LazyRepository) WriteBlob(ID Identifier) (io.Writer, error) { func (l *LazyRepository) WriteBlob(ID Identifier) (io.Writer, error) {
path := l.DataPath(ID) path := l.DataPath(ID)
slog.Debug("loading write buffer...", "id", ID)
dst, err := os.OpenFile(filepath.Join(path, "data.tar.gz"), os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0740) dst, err := os.OpenFile(filepath.Join(path, "data.tar.gz"), os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0740)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to open destination file: %w", err) return nil, fmt.Errorf("failed to open destination file: %w", err)
@@ -182,6 +191,7 @@ func (l *LazyRepository) WriteBlob(ID Identifier) (io.Writer, error) {
func (l *LazyRepository) WriteMetadata(id GameIdentifier, m Metadata) error { func (l *LazyRepository) WriteMetadata(id GameIdentifier, m Metadata) error {
path := l.DataPath(id) path := l.DataPath(id)
slog.Debug("writing metadata", "id", id, "metadata", m)
dst, err := os.OpenFile(filepath.Join(path, "metadata.json"), os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0740) dst, err := os.OpenFile(filepath.Join(path, "metadata.json"), os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0740)
if err != nil { if err != nil {
return fmt.Errorf("failed to open destination file: %w", err) return fmt.Errorf("failed to open destination file: %w", err)
@@ -199,6 +209,7 @@ func (l *LazyRepository) WriteMetadata(id GameIdentifier, m Metadata) error {
func (l *LazyRepository) Metadata(id GameIdentifier) (Metadata, error) { func (l *LazyRepository) Metadata(id GameIdentifier) (Metadata, error) {
path := l.DataPath(id) path := l.DataPath(id)
slog.Debug("loading metadata", "id", id)
src, err := os.OpenFile(filepath.Join(path, "metadata.json"), os.O_RDONLY, 0) src, err := os.OpenFile(filepath.Join(path, "metadata.json"), os.O_RDONLY, 0)
if err != nil { if err != nil {
if errors.Is(err, os.ErrNotExist) { if errors.Is(err, os.ErrNotExist) {
@@ -220,6 +231,7 @@ func (l *LazyRepository) Metadata(id GameIdentifier) (Metadata, error) {
return Metadata{}, fmt.Errorf("failed to open archive: %w", err) return Metadata{}, fmt.Errorf("failed to open archive: %w", err)
} }
slog.Debug("loading md5 hash", "id", id)
m.MD5, err = hash.FileMD5(filepath.Join(path, "data.tar.gz")) m.MD5, err = hash.FileMD5(filepath.Join(path, "data.tar.gz"))
if err != nil { if err != nil {
return Metadata{}, fmt.Errorf("failed to calculate md5: %w", err) return Metadata{}, fmt.Errorf("failed to calculate md5: %w", err)
@@ -231,6 +243,7 @@ func (l *LazyRepository) Metadata(id GameIdentifier) (Metadata, error) {
func (l *LazyRepository) Backup(id BackupIdentifier) (Backup, error) { func (l *LazyRepository) Backup(id BackupIdentifier) (Backup, error) {
path := l.DataPath(id) path := l.DataPath(id)
slog.Debug("loading hist metadata", "id", id)
fs, err := os.Stat(filepath.Join(path, "data.tar.gz")) fs, err := os.Stat(filepath.Join(path, "data.tar.gz"))
if err != nil { if err != nil {
if errors.Is(err, os.ErrNotExist) { if errors.Is(err, os.ErrNotExist) {
@@ -239,6 +252,7 @@ func (l *LazyRepository) Backup(id BackupIdentifier) (Backup, error) {
return Backup{}, fmt.Errorf("corrupted datastore: failed to open metadata: %w", err) return Backup{}, fmt.Errorf("corrupted datastore: failed to open metadata: %w", err)
} }
slog.Debug("loading md5 hash", "id", id)
h, err := hash.FileMD5(filepath.Join(path, "data.tar.gz")) h, err := hash.FileMD5(filepath.Join(path, "data.tar.gz"))
if err != nil { if err != nil {
return Backup{}, fmt.Errorf("corrupted datastore: failed to open metadata: %w", err) return Backup{}, fmt.Errorf("corrupted datastore: failed to open metadata: %w", err)
@@ -274,6 +288,7 @@ func (l *LazyRepository) LastScan(id GameIdentifier) (time.Time, error) {
func (l *LazyRepository) ResetLastScan(id GameIdentifier) error { func (l *LazyRepository) ResetLastScan(id GameIdentifier) error {
path := l.DataPath(id) path := l.DataPath(id)
slog.Debug("resetting last scan datetime for", "id", id)
f, err := os.OpenFile(filepath.Join(path, ".last_run"), os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0740) f, err := os.OpenFile(filepath.Join(path, ".last_run"), os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0740)
if err != nil { if err != nil {
return fmt.Errorf("failed to open file: %w", err) return fmt.Errorf("failed to open file: %w", err)
@@ -289,9 +304,10 @@ func (l *LazyRepository) ResetLastScan(id GameIdentifier) error {
return nil return nil
} }
func (l *LazyRepository) ReadBlob(id Identifier) (io.Reader, error) { func (l *LazyRepository) ReadBlob(id Identifier) (io.ReadSeekCloser, error) {
path := l.DataPath(id) path := l.DataPath(id)
slog.Debug("loading read buffer...", "id", id)
dst, err := os.OpenFile(filepath.Join(path, "data.tar.gz"), os.O_RDONLY, 0) dst, err := os.OpenFile(filepath.Join(path, "data.tar.gz"), os.O_RDONLY, 0)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to open blob: %w", err) return nil, fmt.Errorf("failed to open blob: %w", err)
@@ -344,6 +360,7 @@ func (l *LazyRepository) Remote(id GameIdentifier) (*Remote, error) {
func (l *LazyRepository) Remove(id GameIdentifier) error { func (l *LazyRepository) Remove(id GameIdentifier) error {
path := l.DataPath(id) path := l.DataPath(id)
slog.Debug("removing data", "id", id)
if err := os.RemoveAll(path); err != nil { if err := os.RemoveAll(path); err != nil {
return fmt.Errorf("failed to remove game folder from the datastore: %w", err) return fmt.Errorf("failed to remove game folder from the datastore: %w", err)
} }