package scanner import ( "crypto/rand" "encoding/hex" "os" "path/filepath" "time" "yoresee_dropbox/internal/store" ) type Scanner struct { store *store.Store workspace string interval time.Duration stopCh chan struct{} } func New(s *store.Store, workspace string, interval time.Duration) *Scanner { return &Scanner{ store: s, workspace: workspace, interval: interval, stopCh: make(chan struct{}), } } func (sc *Scanner) Start() { go sc.run() } func (sc *Scanner) Stop() { close(sc.stopCh) } func (sc *Scanner) run() { ticker := time.NewTicker(sc.interval) defer ticker.Stop() sc.scan() for { select { case <-sc.stopCh: return case <-ticker.C: sc.scan() } } } func (sc *Scanner) scan() { sc.scanDir("inbox") sc.scanDir("outbox") } func (sc *Scanner) scanDir(dir string) { dirPath := filepath.Join(sc.workspace, dir) entries, err := os.ReadDir(dirPath) if err != nil { return } dbFiles, err := sc.store.FileList(dir) if err != nil { return } dbMap := make(map[string]*store.File) for _, f := range dbFiles { dbMap[f.StorageName] = f } diskMap := make(map[string]bool) for _, entry := range entries { if entry.IsDir() { continue } info, err := entry.Info() if err != nil { continue } diskMap[entry.Name()] = true if _, exists := dbMap[entry.Name()]; !exists { id := generateUUID() f := &store.File{ ID: id, OriginalName: entry.Name(), StorageName: entry.Name(), Dir: dir, Size: info.Size(), CreatedAt: time.Now().Unix(), } sc.store.FileCreate(f) } } for name, f := range dbMap { if !diskMap[name] { sc.store.FileDelete(f.ID) } } } func generateUUID() string { b := make([]byte, 16) rand.Read(b) return hex.EncodeToString(b) }