package asses import ( "context" "crypto/md5" "encoding/base64" "fmt" "io" "log" "math/rand" "os" "path" "show-rss/src/slow" "time" ) func One(ctx context.Context, p string) error { shortp := path.Join("...", path.Base(path.Dir(p)), path.Base(p)) last, err := checkLast(ctx, p) if err != nil { return err } threshold := 20 + rand.Int()%10 if daysSince := int(time.Since(last.T).Hours()/24); daysSince > threshold { log.Printf("asses.One(%s) // no modified check as %vd since last check", shortp, daysSince) } else if stat, err := os.Stat(p); err != nil { return fmt.Errorf("cannot stat %s: %w", p, err) } else if stat.ModTime() == last.Modified { log.Printf("asses.One(%s) // unmodified since %v", shortp, last.T) return nil } else { log.Printf("asses.One(%s) // modified (%v) is now %v", shortp, last.Modified, stat.ModTime()) } if err := func() error { if len(last.Cksum) > 0 { if last.Modified.IsZero() { log.Printf("asses.One(%s) // assume cksum unchanged given null modified ", shortp) return nil } cksum, err := Cksum(ctx, p) if err != nil { return err } if cksum == last.Cksum { log.Printf("asses.One(%s) // cksum unchanged since %v", shortp, last.T) return nil } } log.Printf("asses.deport(%s)...", shortp) if err := deport(ctx, p); err != nil { return err } return nil }(); err != nil { return err } cksum, err := Cksum(ctx, p) if err != nil { return err } stat, err := os.Stat(p) if err != nil { return err } if err := checked(ctx, p, cksum, stat.ModTime()); err != nil { log.Printf("failed to mark %s checked: %v", shortp, err) return err } return nil } func Cksum(ctx context.Context, p string) (string, error) { f, err := os.Open(p) if err != nil { return "", err } defer f.Close() hasher := md5.New() _, err = io.Copy(hasher, slow.NewReader(ctx, 10_000_000, f)) return base64.StdEncoding.EncodeToString(hasher.Sum(nil)), err }