package database import ( "context" "encoding/hex" "log/slog" "github.com/jackc/pgx/v5" "golang.org/x/crypto/blake2b" "git.jmbit.de/jmb/scanfile/server/internal/sqlc" "git.jmbit.de/jmb/scanfile/server/internal/store" ) // CreateFile() creates the filesystem object and the DB entry for a file func CreateFile(ctx context.Context, name string, fileBytes []byte) (sqlc.File, error) { queries := sqlc.New(pool) file := sqlc.File{ Name: name, } var err error bl2hash := blake2b.Sum256(fileBytes) slog.Debug("calculated Blake2b hash", "file-name", name, "file-bl2", hex.EncodeToString(bl2hash[:]), "file-size", len(fileBytes)) mime, _ := store.GetBytesFileType(fileBytes[:262]) file, err = queries.CreateFile(ctx, sqlc.CreateFileParams{ Name: name, Mimetype: mime, Size: int64(len(fileBytes)), Blake2: bl2hash[:], }) if err == pgx.ErrNoRows { file, err := queries.GetFileByBlake2(ctx, bl2hash[:]) if err != nil { slog.Error("Error saving file to database", "error", err, "file-name", name) return file, err } slog.Debug("File already exists", "file-uuid", file.ID.String(), "file-name", file.Name, "file-bl2", hex.EncodeToString(file.Blake2), "file-size", file.Size, "file-mime", file.Mimetype, "file-description", file.Description.String) return file, nil } if err != nil { slog.Error("Error saving file to database", "error", err, "file-name", name) err = nil } else { slog.Debug("New file created", "file-uuid", file.ID.String(), "file-name", file.Name, "file-bl2", hex.EncodeToString(file.Blake2), "file-size", file.Size, "file-mime", file.Mimetype, "file-description", file.Description.String) } //Using UUIDs instead of the file hash to make switching storage backends easier _, err = store.SaveFile(file.ID.String(), fileBytes) if err != nil { slog.Error("Error saving file to disk", "error", err, "file-uuid", file.ID.String()) errdel := queries.DeleteFile(ctx, file.ID) if errdel != nil { slog.Error("Error deleting file from database", "error", errdel, "file-uuid", file.ID.String()) } return file, err } return file, nil }