blob: 1cc053bdf15bd5063efe9bbdd1706f0ddd5d2d54 [file] [log] [blame]
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +04001package tasks
2
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +04003type Status int
4
5const (
6 StatusPending Status = 0
7 StatusRunning = 1
8 StatusFailed = 2
9 StatusDone = 3
10)
11
12type TaskDoneListener func(err error)
13
14type Task interface {
15 Title() string
16 Start()
17 Status() Status
18 Err() error
19 Subtasks() []Task
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +040020 OnDone(l TaskDoneListener)
21}
22
23type basicTask struct {
Giorgi Lekveishviliab7ff6e2024-03-29 13:11:30 +040024 title string
25 status Status
26 err error
27 listeners []TaskDoneListener
28 beforeStart func()
29 afterDone func()
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +040030}
31
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +040032func newBasicTask(title string) basicTask {
33 return basicTask{
34 title: title,
35 status: StatusPending,
36 err: nil,
37 listeners: make([]TaskDoneListener, 0),
38 }
39}
40
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +040041func (b *basicTask) Title() string {
42 return b.title
43}
44
45func (b *basicTask) Status() Status {
46 return b.status
47}
48
49func (b *basicTask) Err() error {
50 return b.err
51}
52
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +040053func (b *basicTask) OnDone(l TaskDoneListener) {
54 b.listeners = append(b.listeners, l)
55}
56
57func (b *basicTask) callDoneListeners(err error) {
58 for _, l := range b.listeners {
59 go l(err)
60 }
61 if err == nil {
62 b.status = StatusDone
63 } else {
64 b.status = StatusFailed
65 b.err = err
66 }
67}
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +040068
69type leafTask struct {
70 basicTask
71 start func() error
72}
73
74func newLeafTask(title string, start func() error) leafTask {
75 return leafTask{
76 basicTask: newBasicTask(title),
77 start: start,
78 }
79}
80
81func (b *leafTask) Subtasks() []Task {
82 return make([]Task, 0)
83}
84
85func (b *leafTask) Start() {
Giorgi Lekveishviliab7ff6e2024-03-29 13:11:30 +040086 b.status = StatusRunning
87 if b.beforeStart != nil {
88 b.beforeStart()
89 }
90 err := b.start()
91 defer b.callDoneListeners(err)
92 if b.afterDone != nil {
93 b.afterDone()
94 }
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +040095}
96
97type parentTask struct {
98 leafTask
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +040099 subtasks []Task
100 showChildren bool
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400101}
102
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +0400103func newParentTask(title string, showChildren bool, start func() error, subtasks ...Task) parentTask {
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400104 return parentTask{
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +0400105 leafTask: newLeafTask(title, start),
106 subtasks: subtasks,
107 showChildren: showChildren,
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400108 }
109}
110
111func (t *parentTask) Subtasks() []Task {
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +0400112 if t.showChildren {
113 return t.subtasks
114 } else {
115 return make([]Task, 0)
116 }
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400117}
118
119type sequentialParentTask struct {
120 parentTask
121}
122
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +0400123func newSequentialParentTask(title string, showChildren bool, subtasks ...Task) *sequentialParentTask {
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400124 start := func() error {
125 errCh := make(chan error)
126 for i := range subtasks[:len(subtasks)-1] {
127 next := i + 1
128 subtasks[i].OnDone(func(err error) {
129 if err == nil {
130 go subtasks[next].Start()
131 } else {
132 errCh <- err
133 }
134 })
135 }
136 subtasks[len(subtasks)-1].OnDone(func(err error) {
137 errCh <- err
138 })
139 go subtasks[0].Start()
140 return <-errCh
141 }
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400142 return &sequentialParentTask{
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +0400143 parentTask: newParentTask(title, showChildren, start, subtasks...),
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400144 }
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400145}
146
147type concurrentParentTask struct {
148 parentTask
149}
150
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +0400151func newConcurrentParentTask(title string, showChildren bool, subtasks ...Task) *concurrentParentTask {
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400152 start := func() error {
153 errCh := make(chan error)
154 for i := range subtasks {
155 subtasks[i].OnDone(func(err error) {
156 errCh <- err
157 })
158 go subtasks[i].Start()
159 }
Giorgi Lekveishvili0a0ca0e2024-04-01 09:07:41 +0400160 cnt := 0
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400161 for _ = range subtasks {
162 err := <-errCh
163 if err != nil {
164 return err
165 }
Giorgi Lekveishvili0a0ca0e2024-04-01 09:07:41 +0400166 cnt++
167 if cnt == len(subtasks) {
168 break
169 }
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400170 }
171 return nil
172 }
173 return &concurrentParentTask{
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +0400174 parentTask: newParentTask(title, showChildren, start, subtasks...),
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400175 }
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400176}