Feat livestream support (#180)
* experimental livestrea support * test livestream * update wait time detection * update livestream functions * persist and restore livestreams monitor session * fan-in logging * deps update * added live time display * livestream monitor prototype * changed to default logger instead of passing *slog.Logger everywhere * code refactoring, comments
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
// a stupid package name...
|
||||
package server
|
||||
|
||||
import (
|
||||
@@ -22,6 +23,7 @@ import (
|
||||
"github.com/marcopeocchi/yt-dlp-web-ui/server/dbutil"
|
||||
"github.com/marcopeocchi/yt-dlp-web-ui/server/handlers"
|
||||
"github.com/marcopeocchi/yt-dlp-web-ui/server/internal"
|
||||
"github.com/marcopeocchi/yt-dlp-web-ui/server/internal/livestream"
|
||||
"github.com/marcopeocchi/yt-dlp-web-ui/server/logging"
|
||||
middlewares "github.com/marcopeocchi/yt-dlp-web-ui/server/middleware"
|
||||
"github.com/marcopeocchi/yt-dlp-web-ui/server/openid"
|
||||
@@ -44,7 +46,6 @@ type RunConfig struct {
|
||||
type serverConfig struct {
|
||||
frontend fs.FS
|
||||
swagger fs.FS
|
||||
logger *slog.Logger
|
||||
host string
|
||||
port int
|
||||
mdb *internal.MemoryDB
|
||||
@@ -57,9 +58,10 @@ func RunBlocking(cfg *RunConfig) {
|
||||
|
||||
logWriters := []io.Writer{
|
||||
os.Stdout,
|
||||
logging.NewObservableLogger(),
|
||||
logging.NewObservableLogger(), // for web-ui
|
||||
}
|
||||
|
||||
// file based logging
|
||||
if cfg.FileLogging {
|
||||
logger, err := logging.NewRotableLogger(cfg.LogFile)
|
||||
if err != nil {
|
||||
@@ -76,31 +78,33 @@ func RunBlocking(cfg *RunConfig) {
|
||||
logWriters = append(logWriters, logger)
|
||||
}
|
||||
|
||||
logger := slog.New(
|
||||
slog.NewTextHandler(io.MultiWriter(logWriters...), &slog.HandlerOptions{}),
|
||||
)
|
||||
logger := slog.New(slog.NewTextHandler(io.MultiWriter(logWriters...), &slog.HandlerOptions{
|
||||
Level: slog.LevelInfo, // TODO: detect when launched in debug mode -> slog.LevelDebug
|
||||
}))
|
||||
|
||||
// make the new logger the default one with all the new writers
|
||||
slog.SetDefault(logger)
|
||||
|
||||
db, err := sql.Open("sqlite", cfg.DBPath)
|
||||
if err != nil {
|
||||
logger.Error("failed to open database", slog.String("err", err.Error()))
|
||||
slog.Error("failed to open database", slog.String("err", err.Error()))
|
||||
}
|
||||
|
||||
if err := dbutil.Migrate(context.Background(), db); err != nil {
|
||||
logger.Error("failed to init database", slog.String("err", err.Error()))
|
||||
slog.Error("failed to init database", slog.String("err", err.Error()))
|
||||
}
|
||||
|
||||
mq, err := internal.NewMessageQueue(logger)
|
||||
mq, err := internal.NewMessageQueue()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
mq.SetupConsumers()
|
||||
|
||||
go mdb.Restore(mq, logger)
|
||||
go mdb.Restore(mq)
|
||||
|
||||
srv := newServer(serverConfig{
|
||||
frontend: cfg.App,
|
||||
swagger: cfg.Swagger,
|
||||
logger: logger,
|
||||
host: cfg.Host,
|
||||
port: cfg.Port,
|
||||
mdb: &mdb,
|
||||
@@ -109,13 +113,14 @@ func RunBlocking(cfg *RunConfig) {
|
||||
})
|
||||
|
||||
go gracefulShutdown(srv, &mdb)
|
||||
go autoPersist(time.Minute*5, &mdb, logger)
|
||||
go autoPersist(time.Minute*5, &mdb)
|
||||
|
||||
var (
|
||||
network = "tcp"
|
||||
address = fmt.Sprintf("%s:%d", cfg.Host, cfg.Port)
|
||||
)
|
||||
|
||||
// support unix sockets
|
||||
if strings.HasPrefix(cfg.Host, "/") {
|
||||
network = "unix"
|
||||
address = cfg.Host
|
||||
@@ -123,19 +128,30 @@ func RunBlocking(cfg *RunConfig) {
|
||||
|
||||
listener, err := net.Listen(network, address)
|
||||
if err != nil {
|
||||
logger.Error("failed to listen", slog.String("err", err.Error()))
|
||||
slog.Error("failed to listen", slog.String("err", err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
logger.Info("yt-dlp-webui started", slog.String("address", address))
|
||||
slog.Info("yt-dlp-webui started", slog.String("address", address))
|
||||
|
||||
if err := srv.Serve(listener); err != nil {
|
||||
logger.Warn("http server stopped", slog.String("err", err.Error()))
|
||||
slog.Warn("http server stopped", slog.String("err", err.Error()))
|
||||
}
|
||||
}
|
||||
|
||||
func newServer(c serverConfig) *http.Server {
|
||||
service := ytdlpRPC.Container(c.mdb, c.mq, c.logger)
|
||||
lm := livestream.NewMonitor()
|
||||
go lm.Schedule()
|
||||
go lm.Restore()
|
||||
|
||||
go func() {
|
||||
for {
|
||||
lm.Persist()
|
||||
time.Sleep(time.Minute * 5)
|
||||
}
|
||||
}()
|
||||
|
||||
service := ytdlpRPC.Container(c.mdb, c.mq, lm)
|
||||
rpc.Register(service)
|
||||
|
||||
r := chi.NewRouter()
|
||||
@@ -196,10 +212,9 @@ func newServer(c serverConfig) *http.Server {
|
||||
|
||||
// REST API handlers
|
||||
r.Route("/api/v1", rest.ApplyRouter(&rest.ContainerArgs{
|
||||
DB: c.db,
|
||||
MDB: c.mdb,
|
||||
MQ: c.mq,
|
||||
Logger: c.logger,
|
||||
DB: c.db,
|
||||
MDB: c.mdb,
|
||||
MQ: c.mq,
|
||||
}))
|
||||
|
||||
// Logging
|
||||
@@ -227,15 +242,15 @@ func gracefulShutdown(srv *http.Server, db *internal.MemoryDB) {
|
||||
}()
|
||||
}
|
||||
|
||||
func autoPersist(d time.Duration, db *internal.MemoryDB, logger *slog.Logger) {
|
||||
func autoPersist(d time.Duration, db *internal.MemoryDB) {
|
||||
for {
|
||||
if err := db.Persist(); err != nil {
|
||||
logger.Info(
|
||||
slog.Warn(
|
||||
"failed to persisted session",
|
||||
slog.String("err", err.Error()),
|
||||
)
|
||||
}
|
||||
logger.Info("sucessfully persisted session")
|
||||
slog.Debug("sucessfully persisted session")
|
||||
time.Sleep(d)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user