arlo-cleaner/monitor/arlo.go

123 lines
2.4 KiB
Go
Executable File

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)
}