103 lines
2.4 KiB
Go
103 lines
2.4 KiB
Go
|
|
// Package filewite adds a function to write the data stream to a file
|
||
|
|
package filewrite
|
||
|
|
|
||
|
|
import (
|
||
|
|
"context"
|
||
|
|
"fmt"
|
||
|
|
"os"
|
||
|
|
"path"
|
||
|
|
"time"
|
||
|
|
|
||
|
|
"github.com/chathaway-codes/home-sensors/v2/internal/h264video"
|
||
|
|
"github.com/chathaway-codes/home-sensors/v2/internal/watcher/config"
|
||
|
|
"github.com/rs/zerolog/log"
|
||
|
|
)
|
||
|
|
|
||
|
|
var Default = &Mod{}
|
||
|
|
|
||
|
|
type FileWrite struct {
|
||
|
|
cfg *config.Config
|
||
|
|
cancelFunc func()
|
||
|
|
ctx context.Context
|
||
|
|
video *h264video.Video
|
||
|
|
}
|
||
|
|
|
||
|
|
func New(video *h264video.Video, cfg *config.Config) (*FileWrite, error) {
|
||
|
|
ctx, cancelFunc := context.WithCancel(context.Background())
|
||
|
|
|
||
|
|
return &FileWrite{
|
||
|
|
cfg: cfg,
|
||
|
|
cancelFunc: cancelFunc,
|
||
|
|
video: video,
|
||
|
|
ctx: ctx,
|
||
|
|
}, nil
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
// Run launches the commands and begins creating data. It will block until Done is called.
|
||
|
|
func (v *FileWrite) Run() {
|
||
|
|
// Confirm that the target directory is a directory
|
||
|
|
stat, err := os.Stat(v.cfg.LocalCopy)
|
||
|
|
log := log.With().Str("directory", v.cfg.LocalCopy).Logger()
|
||
|
|
if err != nil {
|
||
|
|
log.Fatal().Err(err).Msg("failed to open path")
|
||
|
|
}
|
||
|
|
if !stat.IsDir() {
|
||
|
|
log.Fatal().Msg("path is not directory")
|
||
|
|
}
|
||
|
|
// Start snooping
|
||
|
|
videoCh, codec, done := v.video.Join()
|
||
|
|
defer done()
|
||
|
|
|
||
|
|
// TODO: what do with codec?
|
||
|
|
log.Info().Str("codec", codec).Msg("got video codec")
|
||
|
|
|
||
|
|
now := time.Now()
|
||
|
|
fileName := path.Join(v.cfg.LocalCopy, fmt.Sprintf("%s.h264", now.Format("2006-01-02T15:04:05")))
|
||
|
|
writer, err := os.Create(fileName)
|
||
|
|
if err != nil {
|
||
|
|
log.Fatal().Err(err).Str("file", fileName).Msg("failed to create file")
|
||
|
|
}
|
||
|
|
|
||
|
|
for bytes := range videoCh {
|
||
|
|
select {
|
||
|
|
case <-v.ctx.Done():
|
||
|
|
return
|
||
|
|
default:
|
||
|
|
// do nothing
|
||
|
|
}
|
||
|
|
|
||
|
|
_, err := writer.Write(bytes)
|
||
|
|
if err != nil {
|
||
|
|
log.Fatal().Str("file", fileName).Err(err).Msg("failed to write bytes")
|
||
|
|
}
|
||
|
|
// Split it every half hour or so
|
||
|
|
if time.Since(now) > time.Minute*30 {
|
||
|
|
now = time.Now()
|
||
|
|
if err := writer.Close(); err != nil {
|
||
|
|
log.Fatal().Err(err).Msg("failed to close file")
|
||
|
|
}
|
||
|
|
fileName := path.Join(v.cfg.LocalCopy, fmt.Sprintf("%s.h264", now.Format("2006-01-02T15:04:05")))
|
||
|
|
writer, err = os.Create(fileName)
|
||
|
|
if err != nil {
|
||
|
|
log.Fatal().Err(err).Str("file", fileName).Msg("failed to create file")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Done stops the processing.
|
||
|
|
func (v *FileWrite) Done() {
|
||
|
|
v.cancelFunc()
|
||
|
|
}
|
||
|
|
|
||
|
|
type Mod struct{}
|
||
|
|
|
||
|
|
func (m *Mod) Get(video *h264video.Video) (*FileWrite, error) {
|
||
|
|
cfg, err := config.Default.Get()
|
||
|
|
if err != nil {
|
||
|
|
return nil, err
|
||
|
|
}
|
||
|
|
return New(video, cfg)
|
||
|
|
}
|