diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..7c22fea --- /dev/null +++ b/Dockerfile @@ -0,0 +1,17 @@ +FROM docker.io/alpine AS builder + +LABEL maintainer="vladimir@hodakov.me" + +COPY . /src + +RUN apk add --no-cache go + +RUN cd /src && go build ./cmd/faketunes + +FROM docker.io/alpine + +RUN apk add --no-cache fuse3 ffmpeg + +COPY --from=builder /src/faketunes /bin/faketunes + +ENTRYPOINT [ "/bin/faketunes" ] diff --git a/internal/domains/cacher/cacher.go b/internal/domains/cacher/cacher.go index c3f625a..e12bb95 100644 --- a/internal/domains/cacher/cacher.go +++ b/internal/domains/cacher/cacher.go @@ -20,17 +20,18 @@ type Cacher struct { transcoder domains.Transcoder cacheDir string - cacheMutex sync.RWMutex currentSize int64 maxSize int64 items map[string]*models.CacheItem + itemsMutex sync.RWMutex stat map[string]*models.CacherStat + statMutex sync.RWMutex } func New(app *application.App) *Cacher { return &Cacher{ app: app, - cacheDir: app.Config().Paths.Destination + "./.cache", + cacheDir: app.Config().Paths.Destination + "/.cache", maxSize: app.Config().FakeTunes.CacheSize * 1024 * 1024, items: make(map[string]*models.CacheItem, 0), stat: make(map[string]*models.CacherStat, 0), diff --git a/internal/domains/cacher/files.go b/internal/domains/cacher/files.go index 3065988..1390b59 100644 --- a/internal/domains/cacher/files.go +++ b/internal/domains/cacher/files.go @@ -18,6 +18,8 @@ func (c *Cacher) GetFileDTO(sourcePath string) (*dto.CacheItem, error) { return nil, fmt.Errorf("%w: %w (%w)", ErrCacher, ErrFailedToGetSourceFile, err) } + c.app.Logger().WithField("item", item).Debug("Retrieved cache item") + return models.CacheItemModelToDTO(item), nil } @@ -32,8 +34,8 @@ func (c *Cacher) getFile(sourcePath string) (*models.CacheItem, error) { cacheKey := fmt.Sprintf("%x", hash) cacheFilePath := filepath.Join(c.cacheDir, cacheKey+".m4a") - c.cacheMutex.Lock() - defer c.cacheMutex.Unlock() + c.itemsMutex.Lock() + defer c.itemsMutex.Unlock() // Check if file information exists in cache if item, ok := c.items[cacheKey]; ok { @@ -92,7 +94,7 @@ func (c *Cacher) getFile(sourcePath string) (*models.CacheItem, error) { c.updateCachedStat(sourcePath, size) // TODO: run cleanup on inotify events. - c.cleanup() + // c.cleanup() return item, nil } diff --git a/internal/domains/cacher/stats.go b/internal/domains/cacher/stats.go index 84b2839..285f2b9 100644 --- a/internal/domains/cacher/stats.go +++ b/internal/domains/cacher/stats.go @@ -12,6 +12,9 @@ import ( // getStat returns file size without triggering conversion (for ls/stat) func (c *Cacher) GetStat(sourcePath string) (int64, error) { + c.statMutex.RLock() + defer c.statMutex.RUnlock() + // First check cache if size, ok := c.getCachedStat(sourcePath); ok { return size, nil @@ -43,8 +46,8 @@ func (c *Cacher) GetStat(sourcePath string) (int64, error) { // updateCachedStat updates the stat cache func (c *Cacher) updateCachedStat(sourcePath string, size int64) { - c.cacheMutex.Lock() - defer c.cacheMutex.Unlock() + c.statMutex.Lock() + defer c.statMutex.Unlock() c.stat[sourcePath] = &models.CacherStat{ Size: size, @@ -54,8 +57,8 @@ func (c *Cacher) updateCachedStat(sourcePath string, size int64) { // getCachedStat returns cached file stats func (c *Cacher) getCachedStat(sourcePath string) (int64, bool) { - c.cacheMutex.RLock() - defer c.cacheMutex.RUnlock() + c.statMutex.RLock() + defer c.statMutex.RUnlock() if stat, ok := c.stat[sourcePath]; ok { return stat.Size, true diff --git a/internal/domains/filesystem/music_file.go b/internal/domains/filesystem/music_file.go index 4941162..21d05eb 100644 --- a/internal/domains/filesystem/music_file.go +++ b/internal/domains/filesystem/music_file.go @@ -2,7 +2,6 @@ package filesystem import ( "context" - "log" "os" "path/filepath" "syscall" @@ -123,11 +122,14 @@ func (f *MusicFile) Open(ctx context.Context, flags uint32) (fh fs.FileHandle, f entry, err := f.f.cacher.GetFileDTO(f.sourcePath) if err != nil { - log.Printf("Failed to convert %s to ALAC: %v", filepath.Base(f.sourcePath), err) + f.f.app.Logger().WithError(err).WithField("source file", f.sourcePath). + WithError(err).Error("Failed to convert file to cache") return nil, 0, syscall.EIO } + f.f.app.Logger().WithField("path", entry.Path).Debug("Opening cached file") + file, err := os.Open(entry.Path) if err != nil { return nil, 0, syscall.EIO