diff --git a/chunkStorage.go b/chunkStorage.go index ddb86ce9c..16ba6dbdb 100644 --- a/chunkStorage.go +++ b/chunkStorage.go @@ -2,6 +2,6 @@ package main type ChunkStorage interface { Setup(config Config) - Save(filePath string) string + Save(filePath string, retryCount int) string GenerateRemotePlaylist(playlist string, variant Variant) string } diff --git a/client.go b/client.go index 89f20c881..5f3bd4700 100644 --- a/client.go +++ b/client.go @@ -4,6 +4,7 @@ import ( "fmt" "io" + log "github.com/sirupsen/logrus" "golang.org/x/net/websocket" ) @@ -24,11 +25,11 @@ type Client struct { func NewClient(ws *websocket.Conn, server *Server) *Client { if ws == nil { - panic("ws cannot be nil") + log.Panicln("ws cannot be nil") } if server == nil { - panic("server cannot be nil") + log.Panicln("server cannot be nil") } ch := make(chan *ChatMessage, channelBufSize) diff --git a/config.go b/config.go index 5d2a63b10..d77701772 100644 --- a/config.go +++ b/config.go @@ -3,9 +3,6 @@ package main import ( "fmt" "io/ioutil" - "os" - "path" - "strconv" log "github.com/sirupsen/logrus" @@ -69,7 +66,7 @@ func getConfig() Config { var config Config err = yaml.Unmarshal(yamlFile, &config) if err != nil { - panic(err) + log.Panicln(err) } // fmt.Printf("%+v\n", config) @@ -79,37 +76,37 @@ func getConfig() Config { func checkConfig(config Config) { if config.S3.Enabled && config.IPFS.Enabled { - panic("S3 and IPFS support cannot be enabled at the same time. Choose one.") + log.Panicln("S3 and IPFS support cannot be enabled at the same time. Choose one.") } if config.S3.Enabled { if config.S3.AccessKey == "" || config.S3.Secret == "" { - panic("S3 support requires an access key and secret.") + log.Panicln("S3 support requires an access key and secret.") } if config.S3.Region == "" || config.S3.Endpoint == "" { - panic("S3 support requires a region and endpoint.") + log.Panicln("S3 support requires a region and endpoint.") } if config.S3.Bucket == "" { - panic("S3 support requires a bucket created for storing public video segments.") + log.Panicln("S3 support requires a bucket created for storing public video segments.") } } - if !fileExists(config.PrivateHLSPath) { - os.MkdirAll(path.Join(config.PrivateHLSPath, strconv.Itoa(0)), 0777) - } + // if !fileExists(config.PrivateHLSPath) { + // os.MkdirAll(path.Join(config.PrivateHLSPath, strconv.Itoa(0)), 0777) + // } - if !fileExists(config.PublicHLSPath) { - os.MkdirAll(path.Join(config.PublicHLSPath, strconv.Itoa(0)), 0777) - } + // if !fileExists(config.PublicHLSPath) { + // os.MkdirAll(path.Join(config.PublicHLSPath, strconv.Itoa(0)), 0777) + // } if !fileExists(config.FFMpegPath) { - panic(fmt.Sprintf("ffmpeg does not exist at %s.", config.FFMpegPath)) + log.Panicln(fmt.Sprintf("ffmpeg does not exist at %s.", config.FFMpegPath)) } if config.VideoSettings.EncoderPreset == "" { - panic("A video encoder preset is required to be set in the config file.") + log.Panicln("A video encoder preset is required to be set in the config file.") } } diff --git a/ipfsStorage.go b/ipfsStorage.go index 6208dc26e..fe4aa55f4 100644 --- a/ipfsStorage.go +++ b/ipfsStorage.go @@ -52,12 +52,12 @@ func (s *IPFSStorage) Setup(config Config) { s.createIPFSDirectory("./hls") } -func (s *IPFSStorage) Save(filePath string) string { +func (s *IPFSStorage) Save(filePath string, retryCount int) string { someFile, err := getUnixfsNode(filePath) defer someFile.Close() if err != nil { - panic(fmt.Errorf("Could not get File: %s", err)) + log.Panicln(fmt.Errorf("Could not get File: %s", err)) } opts := []options.UnixfsAddOption{ @@ -70,7 +70,7 @@ func (s *IPFSStorage) Save(filePath string) string { cidFile, err := (*s.ipfs).Unixfs().Add(s.ctx, someFile, opts...) if err != nil { - panic(fmt.Errorf("Could not add File: %s", err)) + log.Panicln(fmt.Errorf("Could not add File: %s", err)) } // fmt.Printf("Added file to IPFS with CID %s\n", cidFile.String()) diff --git a/main.go b/main.go index e485c6353..915e55cd3 100644 --- a/main.go +++ b/main.go @@ -37,18 +37,19 @@ func main() { usingExternalStorage = true } + resetDirectories(configuration) + if usingExternalStorage { storage.Setup(configuration) go monitorVideoContent(configuration.PrivateHLSPath, configuration, storage) } - resetDirectories(configuration) go startRTMPService() - startChatServer() + startWebServer() } -func startChatServer() { +func startWebServer() { // log.SetFlags(log.Lshortfile) // websocket server @@ -63,6 +64,7 @@ func startChatServer() { if path.Ext(r.URL.Path) == ".m3u8" { clientID := getClientIDFromRequest(r) stats.SetClientActive(clientID) + disableCache(&w) } }) @@ -77,6 +79,11 @@ func enableCors(w *http.ResponseWriter) { (*w).Header().Set("Access-Control-Allow-Origin", "*") } +func disableCache(w *http.ResponseWriter) { + (*w).Header().Set("Cache-Control", "no-cache, no-store, must-revalidate") + (*w).Header().Set("Expires", "0") +} + func getStatus(w http.ResponseWriter, r *http.Request) { enableCors(&w) diff --git a/playlistMonitor.go b/playlistMonitor.go index 5cd68d767..71c865dc4 100644 --- a/playlistMonitor.go +++ b/playlistMonitor.go @@ -108,7 +108,7 @@ func monitorVideoContent(pathToMonitor string, configuration Config, storage Chu newObjectPathChannel := make(chan string, 1) go func() { - newObjectPath := storage.Save(path.Join(configuration.PrivateHLSPath, segment.RelativeUploadPath)) + newObjectPath := storage.Save(path.Join(configuration.PrivateHLSPath, segment.RelativeUploadPath), 0) newObjectPathChannel <- newObjectPath }() newObjectPath := <-newObjectPathChannel diff --git a/s3Storage.go b/s3Storage.go index e9b0e0d5d..b3f9b16ed 100644 --- a/s3Storage.go +++ b/s3Storage.go @@ -36,14 +36,14 @@ func (s *S3Storage) Setup(configuration Config) { s.sess = s.connectAWS() } -func (s *S3Storage) Save(filePath string) string { +func (s *S3Storage) Save(filePath string, retryCount int) string { // fmt.Println("Saving", filePath) file, err := os.Open(filePath) defer file.Close() if err != nil { - log.Fatal(err) + log.Errorln(err) } uploader := s3manager.NewUploader(s.sess) @@ -55,7 +55,11 @@ func (s *S3Storage) Save(filePath string) string { }) if err != nil { - panic(err) + log.Errorln(err) + if retryCount < 4 { + log.Println("Retrying...") + s.Save(filePath, retryCount+1) + } } // fmt.Println("Uploaded", filePath, "to", response.Location) @@ -88,7 +92,7 @@ func (s S3Storage) connectAWS() *session.Session { creds := credentials.NewStaticCredentials(s.s3AccessKey, s.s3Secret, "") _, err := creds.Get() if err != nil { - panic(err) + log.Panicln(err) } sess, err := session.NewSession( @@ -101,7 +105,7 @@ func (s S3Storage) connectAWS() *session.Session { ) if err != nil { - panic(err) + log.Panicln(err) } return sess } diff --git a/scripts/build.sh b/scripts/build.sh index dea287fa6..631a62ab0 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -9,6 +9,11 @@ ARCH=(amd64 amd64) # Version VERSION=$1 + +if [[ -z "${VERSION}" ]]; then + echo "Version must be specified when running build" +fi + [[ -z "${VERSION}" ]] && VERSION='unknownver' || VERSION="${VERSION}" GIT_COMMIT=$(git rev-list -1 HEAD) @@ -33,7 +38,10 @@ build() { mkdir -p dist/${NAME}/config + # Default files cp config/config-example.yaml dist/${NAME}/config/config.yaml + cp webroot/static/content-example.md dist/${NAME}/webroot/static/content.md + cp -R webroot/ dist/${NAME}/webroot/ cp -R doc/ dist/${NAME}/doc/ cp README.md dist/${NAME} diff --git a/stats.go b/stats.go index bc8fb9d21..4d12a70d1 100644 --- a/stats.go +++ b/stats.go @@ -145,7 +145,7 @@ func getSavedStats() *Stats { var stats Stats err = json.Unmarshal(jsonFile, &stats) if err != nil { - panic(err) + log.Panicln(err) } return &stats diff --git a/webroot/index.html b/webroot/index.html index d63ddb149..a1e2f75e4 100644 --- a/webroot/index.html +++ b/webroot/index.html @@ -8,9 +8,9 @@ - + - + diff --git a/webroot/js/app.js b/webroot/js/app.js index 5319617f6..e36f07de5 100644 --- a/webroot/js/app.js +++ b/webroot/js/app.js @@ -47,13 +47,10 @@ async function setupApp() { const response = await fetch(pageContentFile); const descriptionMarkdown = await response.text() const descriptionHTML = new showdown.Converter().makeHtml(descriptionMarkdown); - console.log(descriptionHTML) app.description = descriptionHTML; - // Object.assign(this, configData); return this; } catch (error) { console.log(error); - // No config file present. That's ok. It's not required. } } diff --git a/webroot/static/content-example.md b/webroot/static/content-example.md new file mode 100644 index 000000000..6b8f2888b --- /dev/null +++ b/webroot/static/content-example.md @@ -0,0 +1,4 @@ +# Stream description and content can go here. + +1. Edit `content.md` in markdown. +1. And it'll go here. \ No newline at end of file