ffmpeg-playout/main.go

128 lines
3.0 KiB
Go

package main
import (
"errors"
"ffmpeg-playout/playout"
"ffmpeg-playout/store"
"fmt"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/cors"
"github.com/ilyakaznacheev/cleanenv"
jsoniter "github.com/json-iterator/go"
"log"
"time"
)
var json = jsoniter.ConfigCompatibleWithStandardLibrary
type Config struct {
Outputs []string `yaml:"outputs"`
Address string `yaml:"address" env:"ADDRESS" env-default:":3000"`
DefaultDuration string `yaml:"default_duration" env:"DEFAULT_DURATION" env-default:"15"`
PlayoutScript string `yaml:"playoutscript"`
PlayoutScriptPath string `yaml:"playoutscriptpath" env:""`
ProgressDir string `yaml:"tmpdir"`
PrometheusPushGateway string `yaml:"prometheusPushGateway"`
}
type Job struct {
StartAt time.Time `json:"startAt,omitempty"`
StopAt time.Time `json:"stopAt,omitempty"`
Source string `json:"source"`
ID int `json:"id"`
Version string `json:"version"`
}
type ScheduledJob struct {
ID int `json:"id"`
Port string `json:"port"`
Room string `json:"room"`
Version string `json:"version"`
}
func schedulePlayout(s *store.Store) fiber.Handler {
// TODO return custom error
return func(c *fiber.Ctx) error {
var p playout.Job
job := new(Job)
jsonErr := json.Unmarshal(c.Body(), job)
if jsonErr != nil {
log.Println("got defective request: ", jsonErr)
c.SendStatus(400)
return jsonErr
}
if job.Source == "" {
c.SendStatus(400)
return errors.New("Got Empty Source. I can't play »Nothing«")
}
p.ID = job.ID
p.Source = job.Source
p.Version = job.Version
p.StartAt = job.StartAt
if job.StopAt.IsZero() {
p.StopAt = p.StartAt.Add(s.DefaultDuration)
} else {
p.StopAt = job.StopAt
}
var output string
s.RLock()
oldPlayout, playoutExists := s.Playouts[job.ID]
s.RUnlock()
if playoutExists {
oldPlayout.ControlChannel <- "reschedule"
output = oldPlayout.Output
} else {
var err error
s.Lock()
output, err = s.AddPlayout(&p)
s.Unlock()
if err != nil {
c.SendStatus(500)
return fmt.Errorf("can not schedule playout: %s", err)
}
}
c.JSON(ScheduledJob{
ID: p.ID,
Port: output,
Version: p.Version,
})
go func() {
p.Playout(s.Config)
s.DeletePlayout(p.ID)
}()
// staus 409 when no schedule possible
return nil
}
}
var cfg Config
func main() {
// TODO configure config file path via cmd parameter
if err := cleanenv.ReadConfig("config.yml", &cfg); err != nil {
log.Fatal("No configfile: ", err)
}
s, err := store.NewStore(cfg.Outputs, cfg.DefaultDuration, cfg.PlayoutScriptPath, cfg.PlayoutScript, cfg.ProgressDir, cfg.PrometheusPushGateway)
if err != nil {
log.Fatal("Failed to init Store: ", err.Error())
}
app := fiber.New()
app.Use(cors.New())
app.Get("/", func(c *fiber.Ctx) error {
return c.SendString("Hello, World!")
})
app.Post("/schedulePlayout", schedulePlayout(s))
log.Fatal(app.Listen(cfg.Address))
}