blob: 3db704295e4b3b7c8300d3d44ae42e591130f9d6 [file] [log] [blame]
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +04001package tasks
2
gioe72b54f2024-04-22 10:44:41 +04003import (
4 "fmt"
5)
6
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +04007type 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
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +040024 OnDone(l TaskDoneListener)
25}
26
27type basicTask struct {
Giorgi Lekveishviliab7ff6e2024-03-29 13:11:30 +040028 title string
29 status Status
30 err error
31 listeners []TaskDoneListener
32 beforeStart func()
33 afterDone func()
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +040034}
35
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +040036func newBasicTask(title string) basicTask {
37 return basicTask{
38 title: title,
39 status: StatusPending,
40 err: nil,
41 listeners: make([]TaskDoneListener, 0),
42 }
43}
44
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +040045func (b *basicTask) Title() string {
46 return b.title
47}
48
49func (b *basicTask) Status() Status {
50 return b.status
51}
52
53func (b *basicTask) Err() error {
54 return b.err
55}
56
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +040057func (b *basicTask) OnDone(l TaskDoneListener) {
58 b.listeners = append(b.listeners, l)
59}
60
61func (b *basicTask) callDoneListeners(err error) {
gioe72b54f2024-04-22 10:44:41 +040062 if err != nil {
63 fmt.Printf("%s %s\n", b.title, err.Error())
64 }
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +040065 for _, l := range b.listeners {
66 go l(err)
67 }
68 if err == nil {
69 b.status = StatusDone
70 } else {
71 b.status = StatusFailed
72 b.err = err
73 }
74}
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +040075
76type leafTask struct {
77 basicTask
78 start func() error
79}
80
81func newLeafTask(title string, start func() error) leafTask {
82 return leafTask{
83 basicTask: newBasicTask(title),
84 start: start,
85 }
86}
87
88func (b *leafTask) Subtasks() []Task {
89 return make([]Task, 0)
90}
91
92func (b *leafTask) Start() {
Giorgi Lekveishviliab7ff6e2024-03-29 13:11:30 +040093 b.status = StatusRunning
94 if b.beforeStart != nil {
95 b.beforeStart()
96 }
97 err := b.start()
98 defer b.callDoneListeners(err)
99 if b.afterDone != nil {
100 b.afterDone()
101 }
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400102}
103
104type parentTask struct {
105 leafTask
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +0400106 subtasks []Task
107 showChildren bool
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400108}
109
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +0400110func newParentTask(title string, showChildren bool, start func() error, subtasks ...Task) parentTask {
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400111 return parentTask{
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +0400112 leafTask: newLeafTask(title, start),
113 subtasks: subtasks,
114 showChildren: showChildren,
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400115 }
116}
117
118func (t *parentTask) Subtasks() []Task {
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +0400119 if t.showChildren {
120 return t.subtasks
121 } else {
122 return make([]Task, 0)
123 }
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400124}
125
126type sequentialParentTask struct {
127 parentTask
128}
129
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +0400130func newSequentialParentTask(title string, showChildren bool, subtasks ...Task) *sequentialParentTask {
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400131 start := func() error {
132 errCh := make(chan error)
133 for i := range subtasks[:len(subtasks)-1] {
134 next := i + 1
135 subtasks[i].OnDone(func(err error) {
136 if err == nil {
137 go subtasks[next].Start()
138 } else {
139 errCh <- err
140 }
141 })
142 }
143 subtasks[len(subtasks)-1].OnDone(func(err error) {
144 errCh <- err
145 })
146 go subtasks[0].Start()
147 return <-errCh
148 }
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400149 return &sequentialParentTask{
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +0400150 parentTask: newParentTask(title, showChildren, start, subtasks...),
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400151 }
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400152}
153
154type concurrentParentTask struct {
155 parentTask
156}
157
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +0400158func newConcurrentParentTask(title string, showChildren bool, subtasks ...Task) *concurrentParentTask {
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400159 start := func() error {
160 errCh := make(chan error)
161 for i := range subtasks {
162 subtasks[i].OnDone(func(err error) {
163 errCh <- err
164 })
165 go subtasks[i].Start()
166 }
Giorgi Lekveishvili0a0ca0e2024-04-01 09:07:41 +0400167 cnt := 0
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400168 for _ = range subtasks {
169 err := <-errCh
170 if err != nil {
171 return err
172 }
Giorgi Lekveishvili0a0ca0e2024-04-01 09:07:41 +0400173 cnt++
174 if cnt == len(subtasks) {
175 break
176 }
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400177 }
178 return nil
179 }
180 return &concurrentParentTask{
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +0400181 parentTask: newParentTask(title, showChildren, start, subtasks...),
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400182 }
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400183}