2020-05-24 03:57:49 +03:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2020-06-02 10:27:54 +03:00
|
|
|
"encoding/json"
|
2020-05-24 03:57:49 +03:00
|
|
|
"net/http"
|
2020-06-11 23:33:20 +03:00
|
|
|
"path"
|
2020-06-02 02:53:31 +03:00
|
|
|
"strconv"
|
2020-05-24 03:57:49 +03:00
|
|
|
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
|
|
)
|
|
|
|
|
2020-06-17 03:27:55 +03:00
|
|
|
// Build-time injected values
|
|
|
|
var GitCommit string = "unknown"
|
|
|
|
var BuildVersion string = "0.0.0"
|
|
|
|
var BuildType string = "localdev"
|
|
|
|
|
2020-06-03 09:05:15 +03:00
|
|
|
var storage ChunkStorage
|
2020-06-02 02:53:31 +03:00
|
|
|
var configuration = getConfig()
|
2020-06-03 03:35:49 +03:00
|
|
|
var server *Server
|
2020-06-11 09:52:55 +03:00
|
|
|
var stats *Stats
|
2020-06-03 03:35:49 +03:00
|
|
|
|
2020-06-10 11:16:17 +03:00
|
|
|
var usingExternalStorage = false
|
2020-05-30 04:08:33 +03:00
|
|
|
|
2020-06-01 22:15:07 +03:00
|
|
|
func main() {
|
2020-06-18 23:09:54 +03:00
|
|
|
// logrus.SetReportCaller(true)
|
2020-06-17 03:27:55 +03:00
|
|
|
log.StandardLogger().Printf("Owncast v%s/%s (%s)", BuildVersion, BuildType, GitCommit)
|
|
|
|
|
2020-06-09 11:52:15 +03:00
|
|
|
checkConfig(configuration)
|
2020-06-18 23:09:54 +03:00
|
|
|
resetDirectories(configuration)
|
2020-06-18 03:52:47 +03:00
|
|
|
|
2020-06-11 09:52:55 +03:00
|
|
|
stats = getSavedStats()
|
|
|
|
stats.Setup()
|
2020-06-02 02:53:31 +03:00
|
|
|
|
|
|
|
if configuration.IPFS.Enabled {
|
2020-06-03 09:05:15 +03:00
|
|
|
storage = &IPFSStorage{}
|
2020-06-03 11:34:05 +03:00
|
|
|
usingExternalStorage = true
|
|
|
|
} else if configuration.S3.Enabled {
|
|
|
|
storage = &S3Storage{}
|
|
|
|
usingExternalStorage = true
|
|
|
|
}
|
2020-06-03 09:05:15 +03:00
|
|
|
|
2020-06-03 11:34:05 +03:00
|
|
|
if usingExternalStorage {
|
|
|
|
storage.Setup(configuration)
|
2020-06-09 11:52:15 +03:00
|
|
|
go monitorVideoContent(configuration.PrivateHLSPath, configuration, storage)
|
2020-06-02 02:53:31 +03:00
|
|
|
}
|
2020-06-01 22:15:07 +03:00
|
|
|
|
2020-06-18 23:09:54 +03:00
|
|
|
createInitialOfflineState()
|
2020-06-15 09:06:43 +03:00
|
|
|
go startRTMPService()
|
2020-05-24 03:57:49 +03:00
|
|
|
|
2020-06-18 09:01:31 +03:00
|
|
|
startWebServer()
|
2020-06-01 22:15:07 +03:00
|
|
|
}
|
|
|
|
|
2020-06-18 09:01:31 +03:00
|
|
|
func startWebServer() {
|
2020-06-01 22:15:07 +03:00
|
|
|
// websocket server
|
2020-06-03 03:35:49 +03:00
|
|
|
server = NewServer("/entry")
|
2020-06-01 22:15:07 +03:00
|
|
|
go server.Listen()
|
|
|
|
|
|
|
|
// static files
|
2020-06-11 23:33:20 +03:00
|
|
|
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
2020-06-14 03:08:34 +03:00
|
|
|
enableCors(&w)
|
2020-06-11 23:33:20 +03:00
|
|
|
http.ServeFile(w, r, path.Join("webroot", r.URL.Path))
|
|
|
|
|
|
|
|
if path.Ext(r.URL.Path) == ".m3u8" {
|
|
|
|
clientID := getClientIDFromRequest(r)
|
|
|
|
stats.SetClientActive(clientID)
|
2020-06-18 07:02:16 +03:00
|
|
|
disableCache(&w)
|
2020-06-11 23:33:20 +03:00
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2020-06-02 10:27:54 +03:00
|
|
|
http.HandleFunc("/status", getStatus)
|
2020-06-01 22:15:07 +03:00
|
|
|
|
2020-06-02 03:42:36 +03:00
|
|
|
log.Printf("Starting public web server on port %d", configuration.WebServerPort)
|
|
|
|
|
2020-06-02 02:53:31 +03:00
|
|
|
log.Fatal(http.ListenAndServe(":"+strconv.Itoa(configuration.WebServerPort), nil))
|
2020-06-01 22:15:07 +03:00
|
|
|
}
|
2020-06-02 10:27:54 +03:00
|
|
|
|
2020-06-14 03:08:34 +03:00
|
|
|
func enableCors(w *http.ResponseWriter) {
|
|
|
|
(*w).Header().Set("Access-Control-Allow-Origin", "*")
|
|
|
|
}
|
|
|
|
|
2020-06-18 07:02:16 +03:00
|
|
|
func disableCache(w *http.ResponseWriter) {
|
|
|
|
(*w).Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
|
|
|
|
(*w).Header().Set("Expires", "0")
|
|
|
|
}
|
|
|
|
|
2020-06-02 10:27:54 +03:00
|
|
|
func getStatus(w http.ResponseWriter, r *http.Request) {
|
2020-06-14 08:39:02 +03:00
|
|
|
enableCors(&w)
|
|
|
|
|
2020-06-02 10:27:54 +03:00
|
|
|
status := Status{
|
2020-06-11 09:52:55 +03:00
|
|
|
Online: stats.IsStreamConnected(),
|
|
|
|
ViewerCount: stats.GetViewerCount(),
|
|
|
|
OverallMaxViewerCount: stats.GetOverallMaxViewerCount(),
|
|
|
|
SessionMaxViewerCount: stats.GetSessionMaxViewerCount(),
|
2020-06-02 10:27:54 +03:00
|
|
|
}
|
|
|
|
json.NewEncoder(w).Encode(status)
|
|
|
|
}
|
|
|
|
|
|
|
|
func streamConnected() {
|
2020-06-11 09:52:55 +03:00
|
|
|
stats.StreamConnected()
|
|
|
|
|
2020-06-10 11:16:17 +03:00
|
|
|
chunkPath := configuration.PublicHLSPath
|
|
|
|
if usingExternalStorage {
|
|
|
|
chunkPath = configuration.PrivateHLSPath
|
|
|
|
}
|
|
|
|
startThumbnailGenerator(chunkPath)
|
2020-06-02 10:27:54 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func streamDisconnected() {
|
2020-06-11 09:52:55 +03:00
|
|
|
stats.StreamDisconnected()
|
2020-06-16 02:27:58 +03:00
|
|
|
if configuration.EnableOfflineImage {
|
|
|
|
showStreamOfflineState(configuration)
|
|
|
|
}
|
2020-06-02 10:27:54 +03:00
|
|
|
}
|
2020-06-03 03:35:49 +03:00
|
|
|
|
2020-06-11 23:33:20 +03:00
|
|
|
func viewerAdded(clientID string) {
|
|
|
|
stats.SetClientActive(clientID)
|
2020-06-03 03:35:49 +03:00
|
|
|
}
|
|
|
|
|
2020-06-11 23:33:20 +03:00
|
|
|
func viewerRemoved(clientID string) {
|
|
|
|
stats.ViewerDisconnected(clientID)
|
2020-06-03 03:35:49 +03:00
|
|
|
}
|