blob: 4eb834d7533e9e51872b4f0db7baef75038a0f83 [file] [log] [blame]
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +04001package tasks
2
3import (
4 "fmt"
5)
6
7type Status int
8
9const (
10 StatusPending Status = 0
11 StatusRunning = 1
12 StatusFailed = 2
13 StatusDone = 3
14)
15
16type TaskDoneListener func(err error)
17
18type Task interface {
19 Title() string
20 Start()
21 Status() Status
22 Err() error
23 Subtasks() []Task
24 AddSubtask(t Task) error
25 FinalizeSubtasks()
26 OnDone(l TaskDoneListener)
27}
28
29type basicTask struct {
30 title string
31 status Status
32 err error
33 subtasks []Task
34 done []bool
35 finalized bool
36 listeners []TaskDoneListener
37}
38
39func (b *basicTask) Title() string {
40 return b.title
41}
42
43func (b *basicTask) Status() Status {
44 return b.status
45}
46
47func (b *basicTask) Err() error {
48 return b.err
49}
50
51func (b *basicTask) Subtasks() []Task {
52 return b.subtasks
53}
54
55func (b *basicTask) AddSubtask(t Task) error {
56 if b.finalized {
57 return fmt.Errorf("already finalized")
58 }
59 i := len(b.subtasks)
60 b.subtasks = append(b.subtasks, t)
61 b.done = append(b.done, false)
62 t.OnDone(func(err error) {
63 if b.done[i] {
64 panic(fmt.Sprintf("already done: %s", b.subtasks[i].Title()))
65 }
66 b.done[i] = true
67 if err != nil {
68 b.callDoneListeners(err)
69 }
70 if !b.finalized {
71 return
72 }
73 done := 0
74 for _, d := range b.done {
75 if d {
76 done++
77 } else {
78 break
79 }
80 }
81 if done == len(b.subtasks) {
82 b.callDoneListeners(nil)
83 }
84 })
85 return nil
86}
87
88func (b *basicTask) FinalizeSubtasks() {
89 b.finalized = true
90}
91
92func (b *basicTask) OnDone(l TaskDoneListener) {
93 b.listeners = append(b.listeners, l)
94}
95
96func (b *basicTask) callDoneListeners(err error) {
97 for _, l := range b.listeners {
98 go l(err)
99 }
100 if err == nil {
101 b.status = StatusDone
102 } else {
103 b.status = StatusFailed
104 b.err = err
105 }
106}