service.go

 1// Package filetracker provides functionality to track file reads in sessions.
 2package filetracker
 3
 4import (
 5	"context"
 6	"log/slog"
 7	"os"
 8	"path/filepath"
 9	"time"
10
11	"github.com/charmbracelet/crush/internal/db"
12)
13
14// Service defines the interface for tracking file reads in sessions.
15type Service interface {
16	// RecordRead records when a file was read.
17	RecordRead(ctx context.Context, sessionID, path string)
18
19	// LastReadTime returns when a file was last read.
20	// Returns zero time if never read.
21	LastReadTime(ctx context.Context, sessionID, path string) time.Time
22}
23
24type service struct {
25	q *db.Queries
26}
27
28// NewService creates a new file tracker service.
29func NewService(q *db.Queries) Service {
30	return &service{q: q}
31}
32
33// RecordRead records when a file was read.
34func (s *service) RecordRead(ctx context.Context, sessionID, path string) {
35	if err := s.q.RecordFileRead(ctx, db.RecordFileReadParams{
36		SessionID: sessionID,
37		Path:      relpath(path),
38	}); err != nil {
39		slog.Error("Error recording file read", "error", err, "file", path)
40	}
41}
42
43// LastReadTime returns when a file was last read.
44// Returns zero time if never read.
45func (s *service) LastReadTime(ctx context.Context, sessionID, path string) time.Time {
46	readFile, err := s.q.GetFileRead(ctx, db.GetFileReadParams{
47		SessionID: sessionID,
48		Path:      relpath(path),
49	})
50	if err != nil {
51		return time.Time{}
52	}
53
54	return time.Unix(readFile.ReadAt, 0)
55}
56
57func relpath(path string) string {
58	path = filepath.Clean(path)
59	basepath, err := os.Getwd()
60	if err != nil {
61		slog.Warn("Error getting basepath", "error", err)
62		return path
63	}
64	relpath, err := filepath.Rel(basepath, path)
65	if err != nil {
66		slog.Warn("Error getting relpath", "error", err)
67		return path
68	}
69	return relpath
70}