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