147 lines
3.4 KiB
Go
147 lines
3.4 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"
|
|
"net"
|
|
"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"`
|
|
OutputFormat string `yaml:"outputFormat"`
|
|
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,
|
|
})
|
|
if !playoutExists {
|
|
go func() {
|
|
log.Printf("Start Scheduling %v", p.ID)
|
|
Waiting:
|
|
for {
|
|
select {
|
|
case ctrlMsg := <-p.ControlChannel:
|
|
fmt.Println(ctrlMsg)
|
|
continue
|
|
case <-time.After(time.Until(p.StartAt)):
|
|
break Waiting
|
|
}
|
|
}
|
|
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, cfg.OutputFormat)
|
|
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))
|
|
|
|
ln, err := net.Listen("tcp", cfg.Address)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
log.Fatal(app.Listener(ln))
|
|
}
|