Files
gosleep/engine/stages.go
T
forust 8501fd074c feat: initial gosleep-timer implementation
Go TUI sleep timer with modular architecture.
- Config: YAML-based, profile inheritance, auto WM detection
- Engine: timer, executor, stage pipeline (pre→timer→post)
- Modules: workspace (niri/hyprland/kde), media, lock, kill,
  notify, sound, brightness, mute, custom, script
- TUI: bubbletea app with profiles, module toggles, progress bar
- CLI: run, list-profiles, export, import, history, stats
- History: JSONL log with statistics
- QR: config export as ASCII QR
2026-07-03 01:43:22 +02:00

75 lines
1.5 KiB
Go

package engine
import (
"context"
"time"
)
type StageRunner struct {
Timer *Timer
PreCmds []string
PostCmds []string
Events chan TimerEvent
ExecTimeout time.Duration
}
func NewStageRunner(timer *Timer, pre, post []string) *StageRunner {
return &StageRunner{
Timer: timer,
PreCmds: pre,
PostCmds: post,
Events: make(chan TimerEvent, 100),
ExecTimeout: 30 * time.Second,
}
}
func (sr *StageRunner) Run(ctx context.Context) {
defer close(sr.Events)
// PreCmds
for _, cmd := range sr.PreCmds {
result := Execute(ctx, cmd, sr.ExecTimeout)
if result.Err != nil {
sr.Events <- TimerEvent{Stage: StagePre, Status: StatusError, Done: true}
return
}
sr.Events <- TimerEvent{Stage: StagePre, Status: StatusRunning}
}
// Timer
timerEvents := make(chan TimerEvent, 100)
go sr.Timer.Start(ctx, timerEvents)
timerDone := false
timerLoop:
for {
select {
case ev := <-timerEvents:
sr.Events <- ev
if ev.Done {
timerDone = true
break timerLoop
}
case <-ctx.Done():
break timerLoop
}
}
// PostCmds (only on normal timer completion)
if timerDone && sr.Timer.Status == StatusDone {
for _, cmd := range sr.PostCmds {
result := Execute(ctx, cmd, sr.ExecTimeout)
if result.Err != nil {
sr.Events <- TimerEvent{Stage: StagePost, Status: StatusError, Done: true}
return
}
sr.Events <- TimerEvent{Stage: StagePost, Status: StatusRunning}
}
sr.Events <- TimerEvent{Status: StatusDone, Done: true}
}
}
func (sr *StageRunner) Stop() {
sr.Timer.Stop()
}