package monitor import ( "fmt" "local/logb" "local/sandbox/arlo-cleaner/arlo" "local/sandbox/arlo-cleaner/config" "local/sandbox/arlo-cleaner/rclone" "net/http" "path" "sort" "time" ) type Arlo struct { arlo *arlo.Arlo rclone *rclone.RClone } func NewArlo() (*Arlo, error) { rclone, err := rclone.New() if err != nil { return nil, err } arlo, err := arlo.New() return &Arlo{ arlo: arlo, rclone: rclone, }, err } func (a *Arlo) Start() <-chan error { ch := make(chan error) go a.watch(ch) return ch } func (a *Arlo) watch(ch chan<- error) { if err := a.Clean(); err != nil { ch <- err } ticker := time.NewTicker(config.MonitorInterval) for _ = range ticker.C { if err := a.Clean(); err != nil { ch <- err } } } func (a *Arlo) Clean() error { if ok, err := a.arlo.NeedsPruning(); err != nil { return err } else if !ok { logb.Infof("Arlo cleaning not needed") return nil } logb.Infof("Arlo clean commencing...") defer logb.Infof("Arlo clean done") prunes, err := a.pickPrunes() if err != nil { return err } if err := a.archives(prunes); err != nil { return err } return a.arlo.DeleteVideos(prunes) } func (a *Arlo) pickPrunes() ([]*arlo.Video, error) { videos, err := a.list() if err != nil { return nil, err } return a.pickRipe(videos), nil } func (a *Arlo) list() ([]*arlo.Video, error) { return a.arlo.ListSince(time.Now().Add(time.Hour * -1 * 24 * 30)) } func (a *Arlo) pickRipe(videos []*arlo.Video) []*arlo.Video { sort.Slice(videos, func(i, j int) bool { return videos[i].Created.Before(videos[j].Created) }) allowed := config.ArloCapacity retain := len(videos) for i := len(videos) - 1; i >= 0; i-- { sz := videos[i].Size() allowed -= sz if allowed >= 0 { retain = i } } logb.Debugf("found %v videos to purge of %v", retain, len(videos)) return videos[:retain] } func (a *Arlo) archives(videos []*arlo.Video) error { for _, video := range videos { if err := a.archive(video); err != nil { return err } } return nil } func (a *Arlo) archive(video *arlo.Video) error { resp, err := http.Get(video.Loc.String()) if err != nil { return err } defer resp.Body.Close() target := path.Join( config.RCloneName, fmt.Sprintf("%02d", video.Created.Year()), fmt.Sprintf("%02d", video.Created.Month()), fmt.Sprintf("%02d", video.Created.Day()), video.Key(), ) logb.Infof("archiving %v", target) return a.rclone.CopyTo(resp.Body, target) }