12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394 |
- package transcoder
- import (
- "io"
- "net"
- "net/http"
- "os"
- "path/filepath"
- "strings"
- "github.com/owncast/owncast/config"
- "github.com/owncast/owncast/utils"
- log "github.com/sirupsen/logrus"
- )
- // FileWriterReceiverServiceCallback are to be fired when transcoder responses are written to disk.
- type FileWriterReceiverServiceCallback interface {
- SegmentWritten(localFilePath string)
- VariantPlaylistWritten(localFilePath string)
- MasterPlaylistWritten(localFilePath string)
- }
- // FileWriterReceiverService accepts transcoder responses via HTTP and fires the callbacks.
- // It is intended to be the middleman between the transcoder and the storage provider and allows
- // the transcoder process to be completely isolated and even run remotely in the future, as long
- // as it can send HTTP requests to this service with the results.
- type FileWriterReceiverService struct {
- callbacks FileWriterReceiverServiceCallback
- }
- // SetupFileWriterReceiverService will start listening for transcoder responses.
- func (s *FileWriterReceiverService) SetupFileWriterReceiverService(callbacks FileWriterReceiverServiceCallback) {
- s.callbacks = callbacks
- httpServer := http.NewServeMux()
- httpServer.HandleFunc("/", s.uploadHandler)
- localListenerAddress := "127.0.0.1:0"
- listener, err := net.Listen("tcp", localListenerAddress)
- if err != nil {
- log.Fatalln("Unable to start internal video writing service", err)
- }
- listenerPort := strings.Split(listener.Addr().String(), ":")[1]
- config.InternalHLSListenerPort = listenerPort
- log.Traceln("Transcoder response service listening on: " + listenerPort)
- go func() {
- //nolint: gosec
- if err := http.Serve(listener, httpServer); err != nil {
- log.Fatalln("Unable to start internal video writing service", err)
- }
- }()
- }
- func (s *FileWriterReceiverService) uploadHandler(w http.ResponseWriter, r *http.Request) {
- if r.Method != "PUT" {
- http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
- return
- }
- path := r.URL.Path
- writePath := filepath.Join(config.HLSStoragePath, path)
- f, err := os.Create(writePath) //nolint: gosec
- if err != nil {
- returnError(err, w)
- return
- }
- defer f.Close()
- if _, err := io.Copy(f, r.Body); err != nil {
- returnError(err, w)
- return
- }
- s.fileWritten(writePath)
- w.WriteHeader(http.StatusOK)
- }
- func (s *FileWriterReceiverService) fileWritten(path string) {
- if utils.GetRelativePathFromAbsolutePath(path) == "hls/stream.m3u8" {
- s.callbacks.MasterPlaylistWritten(path)
- } else if strings.HasSuffix(path, ".ts") {
- s.callbacks.SegmentWritten(path)
- } else if strings.HasSuffix(path, ".m3u8") {
- s.callbacks.VariantPlaylistWritten(path)
- }
- }
- func returnError(err error, w http.ResponseWriter) {
- log.Debugln(err)
- http.Error(w, http.StatusText(http.StatusInternalServerError)+": "+err.Error(), http.StatusInternalServerError)
- }
|