feat: add daemon mode flag
Adds a `-daemon` flag to run the application in the background without the interactive terminal UI. It outputs log lines to standard output instead of utilizing `charmbracelet/bubbletea`.
This commit is contained in:
@@ -2,3 +2,4 @@ config.toml
|
||||
cookies.json
|
||||
dist/
|
||||
.DS_Store
|
||||
parasocial
|
||||
|
||||
@@ -6,6 +6,7 @@ package main
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/signal"
|
||||
@@ -16,10 +17,13 @@ import (
|
||||
|
||||
// main sets up process cancellation and reports fatal startup errors to stderr.
|
||||
func main() {
|
||||
daemon := flag.Bool("daemon", false, "run as daemon without interactive TUI")
|
||||
flag.Parse()
|
||||
|
||||
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
|
||||
defer stop()
|
||||
|
||||
if err := app.Run(ctx); err != nil {
|
||||
if err := app.Run(ctx, *daemon); err != nil {
|
||||
if errors.Is(err, context.Canceled) {
|
||||
return
|
||||
}
|
||||
|
||||
+4
-1
@@ -9,10 +9,13 @@ import (
|
||||
)
|
||||
|
||||
// Run loads configuration and starts the terminal UI.
|
||||
func Run(ctx context.Context) error {
|
||||
func Run(ctx context.Context, daemon bool) error {
|
||||
cfg, err := config.LoadDefault()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if daemon {
|
||||
return tui.RunDaemon(ctx, tui.Options{Streamers: cfg.Streamers})
|
||||
}
|
||||
return tui.Run(ctx, tui.Options{Streamers: cfg.Streamers})
|
||||
}
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
package tui
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// RunDaemon starts the daemon mode which just logs everything instead of UI.
|
||||
func RunDaemon(ctx context.Context, options Options) error {
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
rt := newRuntime(ctx, options)
|
||||
state := options.AuthState
|
||||
if state == nil {
|
||||
var err error
|
||||
state, err = rt.reuseAuth()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if state == nil {
|
||||
fmt.Println("Starting authentication...")
|
||||
authChan := make(chan AuthUpdate)
|
||||
rt.startAuth(authChan)
|
||||
|
||||
var authErr error
|
||||
for authMsg := range authChan {
|
||||
if authMsg.Line != "" {
|
||||
fmt.Println(authMsg.Line)
|
||||
}
|
||||
if authMsg.Done {
|
||||
if authMsg.Err != nil {
|
||||
authErr = authMsg.Err
|
||||
} else if authMsg.State != nil {
|
||||
state = authMsg.State
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if authErr != nil {
|
||||
return fmt.Errorf("authentication failed: %w", authErr)
|
||||
}
|
||||
fmt.Println("Authentication complete.")
|
||||
}
|
||||
|
||||
fmt.Println("Starting streamer resolution...")
|
||||
streamerChan := make(chan StreamerUpdate)
|
||||
rt.startResolve(state, streamerChan)
|
||||
|
||||
for streamerMsg := range streamerChan {
|
||||
if streamerMsg.Done {
|
||||
break
|
||||
}
|
||||
if streamerMsg.Err != nil {
|
||||
fmt.Printf("Error: %v\n", streamerMsg.Err)
|
||||
}
|
||||
if streamerMsg.IRC != nil {
|
||||
if message, ok := formatIRCChatLine(streamerMsg.IRC.Line); ok {
|
||||
fmt.Printf("[IRC] %s: %s\n", streamerMsg.IRC.Login, message)
|
||||
}
|
||||
}
|
||||
if streamerMsg.Miner != nil {
|
||||
line := strings.TrimSpace(streamerMsg.Miner.Line)
|
||||
if line != "" {
|
||||
fmt.Printf("[Miner] %s: %s\n", streamerMsg.Miner.Login, line)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user