package main import ( "context" "strconv" "go.uber.org/zap" "github.com/strimertul/strimertul/twitch" "github.com/strimertul/strimertul/loyalty" "git.sr.ht/~hamcha/containers" "github.com/nicklaw5/helix/v2" "github.com/strimertul/strimertul/database" "github.com/strimertul/strimertul/http" "github.com/urfave/cli/v2" "github.com/wailsapp/wails/v2/pkg/runtime" ) // App struct type App struct { ctx context.Context cliParams *cli.Context driver database.DatabaseDriver ready *containers.RWSync[bool] db *database.LocalDBClient twitchClient *twitch.Client httpServer *http.Server loyaltyManager *loyalty.Manager } // NewApp creates a new App application struct func NewApp(cliParams *cli.Context) *App { return &App{ cliParams: cliParams, ready: containers.NewRWSync(false), } } // startup is called when the app starts func (a *App) startup(ctx context.Context) { a.ctx = ctx // Make KV hub var err error a.driver, err = database.GetDatabaseDriver(a.cliParams) failOnError(err, "error opening database") // Start database backup task backupOpts := database.BackupOptions{ BackupDir: a.cliParams.String("backup-dir"), BackupInterval: a.cliParams.Int("backup-interval"), MaxBackups: a.cliParams.Int("max-backups"), } if backupOpts.BackupInterval > 0 { go BackupTask(a.driver, backupOpts) } hub := a.driver.Hub() go hub.Run() a.db, err = database.NewLocalClient(hub, logger) failOnError(err, "failed to initialize database module") // Set meta keys _ = a.db.PutKey("stul-meta/version", appVersion) // Create logger and endpoints a.httpServer, err = http.NewServer(a.db, logger) failOnError(err, "could not initialize http server") // Create twitch client a.twitchClient, err = twitch.NewClient(a.db, a.httpServer, logger) failOnError(err, "could not initialize twitch client") // Initialize loyalty system a.loyaltyManager, err = loyalty.NewManager(a.db, a.twitchClient, logger) failOnError(err, "could not initialize loyalty manager") a.ready.Set(true) runtime.EventsEmit(ctx, "ready", true) logger.Info("app is ready") // Start redirecting logs to UI go func() { for entry := range incomingLogs { runtime.EventsEmit(ctx, "log-event", entry) } }() // Run HTTP server failOnError(a.httpServer.Listen(), "HTTP server stopped") } func (a *App) stop(context.Context) { if a.loyaltyManager != nil { warnOnError(a.loyaltyManager.Close(), "could not cleanly close loyalty manager") } if a.twitchClient != nil { warnOnError(a.twitchClient.Close(), "could not cleanly close twitch client") } if a.httpServer != nil { warnOnError(a.httpServer.Close(), "could not cleanly close HTTP server") } warnOnError(a.db.Close(), "could not cleanly close database") warnOnError(a.driver.Close(), "could not close driver") } func (a *App) AuthenticateKVClient(id string) { idInt, err := strconv.ParseInt(id, 10, 64) if err != nil { return } warnOnError(a.driver.Hub().SetAuthenticated(idInt, true), "could not mark session as authenticated", zap.String("session-id", id)) } func (a *App) IsServerReady() bool { return a.ready.Get() } func (a *App) GetKilovoltBind() string { if a.httpServer == nil { return "" } return a.httpServer.Config.Bind } func (a *App) GetTwitchAuthURL() string { return a.twitchClient.GetAuthorizationURL() } func (a *App) GetTwitchLoggedUser() (helix.User, error) { return a.twitchClient.GetLoggedUser() } func (a *App) GetLastLogs() []LogEntry { return lastLogs }