blob: 6d0ec0161a4a9c2451b68620e26346018d4f795a [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 {
24 title string
25 status Status
26 err error
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +040027 listeners []TaskDoneListener
28}
29
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +040030func newBasicTask(title string) basicTask {
31 return basicTask{
32 title: title,
33 status: StatusPending,
34 err: nil,
35 listeners: make([]TaskDoneListener, 0),
36 }
37}
38
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +040039func (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
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +040051func (b *basicTask) OnDone(l TaskDoneListener) {
52 b.listeners = append(b.listeners, l)
53}
54
55func (b *basicTask) callDoneListeners(err error) {
56 for _, l := range b.listeners {
57 go l(err)
58 }
59 if err == nil {
60 b.status = StatusDone
61 } else {
62 b.status = StatusFailed
63 b.err = err
64 }
65}
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +040066
67type leafTask struct {
68 basicTask
69 start func() error
70}
71
72func newLeafTask(title string, start func() error) leafTask {
73 return leafTask{
74 basicTask: newBasicTask(title),
75 start: start,
76 }
77}
78
79func (b *leafTask) Subtasks() []Task {
80 return make([]Task, 0)
81}
82
83func (b *leafTask) Start() {
84 b.callDoneListeners(b.start())
85}
86
87type parentTask struct {
88 leafTask
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +040089 subtasks []Task
90 showChildren bool
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +040091}
92
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +040093func newParentTask(title string, showChildren bool, start func() error, subtasks ...Task) parentTask {
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +040094 return parentTask{
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +040095 leafTask: newLeafTask(title, start),
96 subtasks: subtasks,
97 showChildren: showChildren,
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +040098 }
99}
100
101func (t *parentTask) Subtasks() []Task {
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +0400102 if t.showChildren {
103 return t.subtasks
104 } else {
105 return make([]Task, 0)
106 }
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400107}
108
109type sequentialParentTask struct {
110 parentTask
111}
112
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +0400113func newSequentialParentTask(title string, showChildren bool, subtasks ...Task) *sequentialParentTask {
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400114 start := func() error {
115 errCh := make(chan error)
116 for i := range subtasks[:len(subtasks)-1] {
117 next := i + 1
118 subtasks[i].OnDone(func(err error) {
119 if err == nil {
120 go subtasks[next].Start()
121 } else {
122 errCh <- err
123 }
124 })
125 }
126 subtasks[len(subtasks)-1].OnDone(func(err error) {
127 errCh <- err
128 })
129 go subtasks[0].Start()
130 return <-errCh
131 }
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400132 return &sequentialParentTask{
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +0400133 parentTask: newParentTask(title, showChildren, start, subtasks...),
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400134 }
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400135}
136
137type concurrentParentTask struct {
138 parentTask
139}
140
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +0400141func newConcurrentParentTask(title string, showChildren bool, subtasks ...Task) *concurrentParentTask {
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400142 start := func() error {
143 errCh := make(chan error)
144 for i := range subtasks {
145 subtasks[i].OnDone(func(err error) {
146 errCh <- err
147 })
148 go subtasks[i].Start()
149 }
150 return <-errCh
151 for _ = range subtasks {
152 err := <-errCh
153 if err != nil {
154 return err
155 }
156 }
157 return nil
158 }
159 return &concurrentParentTask{
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +0400160 parentTask: newParentTask(title, showChildren, start, subtasks...),
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400161 }
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400162}