diff --git a/cmd/survey/runner.go b/cmd/survey/runner.go index def5759..c41e870 100644 --- a/cmd/survey/runner.go +++ b/cmd/survey/runner.go @@ -16,6 +16,14 @@ func taskLoop(ctx context.Context, surveyTasks []*task.Task, interfaces []task.I t.SetInterface(interfaces[interfaceIndex]) + doneChan := make(chan bool, 1) + quitChan := make(chan bool, 1) + feedbackChan := make(chan task.ValidationFeedback, 10) + + if validated, ok := interfaces[interfaceIndex].(task.ValidatedInterface); ok { + validated.SetChannels(feedbackChan, quitChan) + } + if err := t.Initialize(ctx); err != nil { return fmt.Errorf("failed to initialize task: %w", err) } @@ -24,16 +32,27 @@ func taskLoop(ctx context.Context, surveyTasks []*task.Task, interfaces []task.I return returnIfUserQuit(err, "failed to display task introduction screen") } - if err := t.StartInterface(ctx, t.Config); err != nil { - return returnIfUserQuit(err, "failed to start task interface") - } + t.SetChannels(feedbackChan, doneChan, quitChan) - ok, err := t.Validate(ctx) - if err != nil { - return returnIfUserQuit(err, "validation error") - } - if !ok { - return fmt.Errorf("task validation failed: task did not meet requirements") + go t.StartValidationLoop(ctx) + + interfaceDone := make(chan error, 1) + go func() { + interfaceDone <- t.StartInterface(ctx, t.Config) + }() + + select { + case <-doneChan: + close(quitChan) + <-interfaceDone + fmt.Println("Task completed successfully!") + + case err := <-interfaceDone: + close(quitChan) + if err != nil { + return returnIfUserQuit(err, "failed to start task interface") + } + fmt.Println("Task incomplete - you exited early") } if err := t.StartQuestionnaire(); err != nil { diff --git a/pkg/task/task.go b/pkg/task/task.go index 4358e56..d71198f 100644 --- a/pkg/task/task.go +++ b/pkg/task/task.go @@ -3,6 +3,7 @@ package task import ( "context" "fmt" + "time" "github.com/LazyBachelor/LazyPM/internal/service" tea "github.com/charmbracelet/bubbletea" @@ -18,6 +19,10 @@ type Task struct { dbStateFunc DbStateFunc svc *service.Services + + feedbackChan chan ValidationFeedback + doneChan chan bool + quitChan chan bool } func NewTask(svc *service.Services, aboutScreen tea.Model, questionnaire tea.Model) *Task { @@ -93,3 +98,43 @@ func (t *Task) SetDbStateFunc(fn DbStateFunc) { func (t *Task) SetValidateFunc(fn ValidateFunc) { t.validateFunc = fn } + +func (t *Task) SetChannels(feedbackChan chan ValidationFeedback, doneChan chan bool, quitChan chan bool) { + t.feedbackChan = feedbackChan + t.doneChan = doneChan + t.quitChan = quitChan +} + +func (t *Task) StartValidationLoop(ctx context.Context) { + ticker := time.NewTicker(1 * time.Second) + defer ticker.Stop() + + for { + select { + case <-ticker.C: + ok, err := t.Validate(ctx) + feedback := ValidationFeedback{ + Timestamp: time.Now(), + } + if ok { + feedback.Success = true + feedback.Message = "Task completed successfully!" + t.feedbackChan <- feedback + t.doneChan <- true + return + } else { + feedback.Success = false + if err != nil { + feedback.Message = err.Error() + } else { + feedback.Message = "Task not yet complete" + } + t.feedbackChan <- feedback + } + case <-t.quitChan: + return + case <-ctx.Done(): + return + } + } +} diff --git a/pkg/task/types.go b/pkg/task/types.go index 524ee2a..d3de92e 100644 --- a/pkg/task/types.go +++ b/pkg/task/types.go @@ -3,6 +3,7 @@ package task import ( "context" "errors" + "time" "github.com/LazyBachelor/LazyPM/internal/service" ) @@ -18,3 +19,19 @@ type Interface interface { type ConfigFunc func() TaskConfig type ValidateFunc func(context.Context, *service.Services) (ok bool, err error) type DbStateFunc func(context.Context, *service.Services) error + +type ValidationFeedback struct { + Success bool + Message string + Timestamp time.Time +} + +type ValidationObserver interface { + OnValidationUpdate(feedback ValidationFeedback) + OnTaskComplete() +} + +type ValidatedInterface interface { + Interface + SetChannels(feedbackChan chan ValidationFeedback, quitChan chan bool) +}