blob: 75e8a6826a2618f25c7f3222db9ea1ee3c858bed [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
89 subtasks []Task
90}
91
92func newParentTask(title string, start func() error, subtasks ...Task) parentTask {
93 return parentTask{
94 leafTask: newLeafTask(title, start),
95 subtasks: subtasks,
96 }
97}
98
99func (t *parentTask) Subtasks() []Task {
100 return t.subtasks
101}
102
103type sequentialParentTask struct {
104 parentTask
105}
106
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400107func newSequentialParentTask(title string, subtasks ...Task) *sequentialParentTask {
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400108 start := func() error {
109 errCh := make(chan error)
110 for i := range subtasks[:len(subtasks)-1] {
111 next := i + 1
112 subtasks[i].OnDone(func(err error) {
113 if err == nil {
114 go subtasks[next].Start()
115 } else {
116 errCh <- err
117 }
118 })
119 }
120 subtasks[len(subtasks)-1].OnDone(func(err error) {
121 errCh <- err
122 })
123 go subtasks[0].Start()
124 return <-errCh
125 }
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400126 return &sequentialParentTask{
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400127 parentTask: newParentTask(title, start, subtasks...),
128 }
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400129}
130
131type concurrentParentTask struct {
132 parentTask
133}
134
135func newConcurrentParentTask(title string, subtasks ...Task) *concurrentParentTask {
136 start := func() error {
137 errCh := make(chan error)
138 for i := range subtasks {
139 subtasks[i].OnDone(func(err error) {
140 errCh <- err
141 })
142 go subtasks[i].Start()
143 }
144 return <-errCh
145 for _ = range subtasks {
146 err := <-errCh
147 if err != nil {
148 return err
149 }
150 }
151 return nil
152 }
153 return &concurrentParentTask{
154 parentTask: newParentTask(title, start, subtasks...),
155 }
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400156}