mirror of
https://github.com/bluenviron/mediamtx
synced 2024-12-15 19:24:55 +00:00
144 lines
2.3 KiB
Go
144 lines
2.3 KiB
Go
package record
|
|
|
|
import (
|
|
"context"
|
|
"io/fs"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/bluenviron/mediamtx/internal/logger"
|
|
)
|
|
|
|
func commonPath(v string) string {
|
|
common := ""
|
|
remaining := v
|
|
|
|
for {
|
|
i := strings.IndexAny(remaining, "\\/")
|
|
if i < 0 {
|
|
break
|
|
}
|
|
|
|
var part string
|
|
part, remaining = remaining[:i+1], remaining[i+1:]
|
|
|
|
if strings.Contains(part, "%") {
|
|
break
|
|
}
|
|
|
|
common += part
|
|
}
|
|
|
|
if len(common) > 0 {
|
|
common = common[:len(common)-1]
|
|
}
|
|
|
|
return common
|
|
}
|
|
|
|
// Cleaner removes expired recordings from disk.
|
|
type Cleaner struct {
|
|
ctx context.Context
|
|
ctxCancel func()
|
|
path string
|
|
deleteAfter time.Duration
|
|
parent logger.Writer
|
|
|
|
done chan struct{}
|
|
}
|
|
|
|
// NewCleaner allocates a Cleaner.
|
|
func NewCleaner(
|
|
recordPath string,
|
|
deleteAfter time.Duration,
|
|
parent logger.Writer,
|
|
) *Cleaner {
|
|
recordPath += ".mp4"
|
|
|
|
ctx, ctxCancel := context.WithCancel(context.Background())
|
|
|
|
c := &Cleaner{
|
|
ctx: ctx,
|
|
ctxCancel: ctxCancel,
|
|
path: recordPath,
|
|
deleteAfter: deleteAfter,
|
|
parent: parent,
|
|
done: make(chan struct{}),
|
|
}
|
|
|
|
go c.run()
|
|
|
|
return c
|
|
}
|
|
|
|
// Close closes the Cleaner.
|
|
func (c *Cleaner) Close() {
|
|
c.ctxCancel()
|
|
<-c.done
|
|
}
|
|
|
|
// Log is the main logging function.
|
|
func (c *Cleaner) Log(level logger.Level, format string, args ...interface{}) {
|
|
c.parent.Log(level, "[record cleaner]"+format, args...)
|
|
}
|
|
|
|
func (c *Cleaner) run() {
|
|
defer close(c.done)
|
|
|
|
interval := 30 * 60 * time.Second
|
|
if interval > (c.deleteAfter / 2) {
|
|
interval = c.deleteAfter / 2
|
|
}
|
|
|
|
c.doRun() //nolint:errcheck
|
|
|
|
for {
|
|
select {
|
|
case <-time.After(interval):
|
|
c.doRun() //nolint:errcheck
|
|
|
|
case <-c.ctx.Done():
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
func (c *Cleaner) doRun() error {
|
|
commonPath := commonPath(c.path)
|
|
now := timeNow()
|
|
|
|
filepath.Walk(commonPath, func(path string, info fs.FileInfo, err error) error { //nolint:errcheck
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if !info.IsDir() {
|
|
params := decodeRecordPath(c.path, path)
|
|
if params != nil {
|
|
if now.Sub(params.time) > c.deleteAfter {
|
|
c.Log(logger.Debug, "removing %s", path)
|
|
os.Remove(path)
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
})
|
|
|
|
filepath.Walk(commonPath, func(path string, info fs.FileInfo, err error) error { //nolint:errcheck
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if info.IsDir() {
|
|
os.Remove(path)
|
|
}
|
|
|
|
return nil
|
|
})
|
|
|
|
return nil
|
|
}
|