- http.Server with ReadHeaderTimeout/IdleTimeout (no read/write timeouts: /stream/ is long-lived) - shared outbound clients: providerHTTPClient (5m), apiHTTPClient (30s), imgcache client (30s) - imgcache: download outside the lock, per-item helper, cache URL uses the file name not the fs path - writeFileAtomic (temp + fsync + rename) for settings/xepg/pms/urls/authentication JSON - one package-level logMu for WebScreenLog and notifications; ring buffer keeps the newest lines - notifications evict the oldest instead of random map entries - xepg XMLTV file removal rebuilt after the loop; data.go range-mutation removed - API handler returns after error body; WS request/response fresh per command - checked type assertions in data/backup/provider/screen - SIGINT/SIGTERM handled in main via src.Shutdown(); fatal paths exit 1
202 lines
4.4 KiB
Go
202 lines
4.4 KiB
Go
// Copyright 2019 marmei. All rights reserved.
|
|
// Use of this source code is governed by a MIT license that can be found in the
|
|
// LICENSE file.
|
|
// GitHub: https://github.com/xteve-project/xTeVe
|
|
|
|
package main
|
|
|
|
import (
|
|
"flag"
|
|
"fmt"
|
|
"os"
|
|
"os/signal"
|
|
"path/filepath"
|
|
"runtime"
|
|
"strings"
|
|
"syscall"
|
|
|
|
"xteve/src"
|
|
)
|
|
|
|
// Name : Programmname
|
|
const Name = "xTeVe"
|
|
|
|
// Version : Version, die Build Nummer wird in der main func geparst.
|
|
// Can be overwritten at build time: -ldflags "-X main.Version=..."
|
|
var Version = "2.2.0.0201"
|
|
|
|
// DBVersion : Datanbank Version
|
|
const DBVersion = "2.1.0"
|
|
|
|
// APIVersion : API Version
|
|
const APIVersion = "1.1.0"
|
|
|
|
var homeDirectory = fmt.Sprintf("%s%s.%s%s", src.GetUserHomeDirectory(), string(os.PathSeparator), strings.ToLower(Name), string(os.PathSeparator))
|
|
var samplePath = fmt.Sprintf("%spath%sto%sxteve%s", string(os.PathSeparator), string(os.PathSeparator), string(os.PathSeparator), string(os.PathSeparator))
|
|
var sampleRestore = fmt.Sprintf("%spath%sto%sfile%s", string(os.PathSeparator), string(os.PathSeparator), string(os.PathSeparator), string(os.PathSeparator))
|
|
|
|
var configFolder = flag.String("config", "", ": Config Folder ["+samplePath+"] (default: "+homeDirectory+")")
|
|
var port = flag.String("port", "", ": Server port [34400] (default: 34400)")
|
|
var restore = flag.String("restore", "", ": Restore from backup ["+sampleRestore+"xteve_backup.zip]")
|
|
|
|
var gitBranch = flag.String("branch", "", ": Git Branch [master|beta] (default: master)")
|
|
var debug = flag.Int("debug", 0, ": Debug level [0 - 3] (default: 0)")
|
|
var info = flag.Bool("info", false, ": Show system info")
|
|
var h = flag.Bool("h", false, ": Show help")
|
|
|
|
// Aktiviert den Entwicklungsmodus. Für den Webserver werden dann die lokalen Dateien verwendet.
|
|
var dev = flag.Bool("dev", false, ": Activates the developer mode, the source code must be available. The local files for the web interface are used.")
|
|
|
|
func main() {
|
|
|
|
// Build-Nummer von der Versionsnummer trennen
|
|
var build = strings.Split(Version, ".")
|
|
|
|
var system = &src.System
|
|
system.APIVersion = APIVersion
|
|
system.Build = build[len(build)-1:][0]
|
|
system.DBVersion = DBVersion
|
|
system.Name = Name
|
|
system.Version = strings.Join(build[0:len(build)-1], ".")
|
|
|
|
// Panic !!!
|
|
defer func() {
|
|
|
|
if r := recover(); r != nil {
|
|
|
|
fmt.Println()
|
|
fmt.Println("* * * * * FATAL ERROR * * * * *")
|
|
fmt.Println("OS: ", runtime.GOOS)
|
|
fmt.Println("Arch:", runtime.GOARCH)
|
|
fmt.Println("Err: ", r)
|
|
fmt.Println()
|
|
|
|
pc := make([]uintptr, 20)
|
|
runtime.Callers(2, pc)
|
|
|
|
for i := range pc {
|
|
|
|
if runtime.FuncForPC(pc[i]) != nil {
|
|
|
|
f := runtime.FuncForPC(pc[i])
|
|
file, line := f.FileLine(pc[i])
|
|
|
|
if string(file)[0:1] != "?" {
|
|
fmt.Printf("%s:%d %s\n", filepath.Base(file), line, f.Name())
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fmt.Println()
|
|
fmt.Println("* * * * * * * * * * * * * * * *")
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
flag.Parse()
|
|
|
|
if *h {
|
|
flag.Usage()
|
|
return
|
|
}
|
|
|
|
system.Dev = *dev
|
|
|
|
// Systeminformationen anzeigen
|
|
if *info {
|
|
|
|
system.Flag.Info = true
|
|
|
|
err := src.Init()
|
|
if err != nil {
|
|
src.ShowError(err, 0)
|
|
os.Exit(1)
|
|
}
|
|
|
|
src.ShowSystemInfo()
|
|
return
|
|
|
|
}
|
|
|
|
// Webserver Port
|
|
if len(*port) > 0 {
|
|
system.Flag.Port = *port
|
|
}
|
|
|
|
// Branch
|
|
system.Flag.Branch = *gitBranch
|
|
if len(system.Flag.Branch) > 0 {
|
|
fmt.Println("Git Branch is now:", system.Flag.Branch)
|
|
}
|
|
|
|
// Debug Level
|
|
system.Flag.Debug = *debug
|
|
if system.Flag.Debug > 3 {
|
|
flag.Usage()
|
|
return
|
|
}
|
|
|
|
// Speicherort für die Konfigurationsdateien
|
|
if len(*configFolder) > 0 {
|
|
system.Folder.Config = *configFolder
|
|
}
|
|
|
|
// Backup wiederherstellen
|
|
if len(*restore) > 0 {
|
|
|
|
system.Flag.Restore = *restore
|
|
|
|
err := src.Init()
|
|
if err != nil {
|
|
src.ShowError(err, 0)
|
|
os.Exit(1)
|
|
}
|
|
|
|
err = src.XteveRestoreFromCLI(*restore)
|
|
if err != nil {
|
|
src.ShowError(err, 0)
|
|
os.Exit(1)
|
|
}
|
|
|
|
os.Exit(0)
|
|
}
|
|
|
|
err := src.Init()
|
|
if err != nil {
|
|
src.ShowError(err, 0)
|
|
os.Exit(1)
|
|
}
|
|
|
|
err = src.StartSystem(false)
|
|
if err != nil {
|
|
src.ShowError(err, 0)
|
|
os.Exit(1)
|
|
}
|
|
|
|
// Graceful stop on SIGINT / SIGTERM: say goodbye on the network (SSDP)
|
|
// and exit cleanly instead of letting the runtime kill the process.
|
|
go func() {
|
|
quit := make(chan os.Signal, 1)
|
|
signal.Notify(quit, os.Interrupt, syscall.SIGTERM)
|
|
<-quit
|
|
src.Shutdown()
|
|
os.Exit(0)
|
|
}()
|
|
|
|
err = src.InitMaintenance()
|
|
if err != nil {
|
|
src.ShowError(err, 0)
|
|
os.Exit(1)
|
|
}
|
|
|
|
err = src.StartWebserver()
|
|
if err != nil {
|
|
src.ShowError(err, 0)
|
|
os.Exit(1)
|
|
}
|
|
|
|
}
|