mirror of https://github.com/stashapp/stash.git
177 lines
3.8 KiB
Go
177 lines
3.8 KiB
Go
package job
|
|
|
|
import "sync"
|
|
|
|
// ProgressIndefinite is the special percent value to indicate that the
|
|
// percent progress is not known.
|
|
const ProgressIndefinite float64 = -1
|
|
|
|
// Progress is used by JobExec to communicate updates to the job's progress to
|
|
// the JobManager.
|
|
type Progress struct {
|
|
defined bool
|
|
processed int
|
|
total int
|
|
percent float64
|
|
currentTasks []*task
|
|
|
|
mutex sync.Mutex
|
|
updater *updater
|
|
}
|
|
|
|
type task struct {
|
|
description string
|
|
}
|
|
|
|
func (p *Progress) updated() {
|
|
var details []string
|
|
for _, t := range p.currentTasks {
|
|
details = append(details, t.description)
|
|
}
|
|
|
|
p.updater.updateProgress(p.percent, details)
|
|
}
|
|
|
|
// Indefinite sets the progress to an indefinite amount.
|
|
func (p *Progress) Indefinite() {
|
|
p.mutex.Lock()
|
|
defer p.mutex.Unlock()
|
|
|
|
p.defined = false
|
|
p.total = 0
|
|
p.calculatePercent()
|
|
}
|
|
|
|
// Definite notifies that the total is known.
|
|
func (p *Progress) Definite() {
|
|
p.mutex.Lock()
|
|
defer p.mutex.Unlock()
|
|
|
|
p.defined = true
|
|
p.calculatePercent()
|
|
}
|
|
|
|
// SetTotal sets the total number of work units and sets definite to true.
|
|
// This is used to calculate the progress percentage.
|
|
func (p *Progress) SetTotal(total int) {
|
|
p.mutex.Lock()
|
|
defer p.mutex.Unlock()
|
|
|
|
p.total = total
|
|
p.defined = true
|
|
p.calculatePercent()
|
|
}
|
|
|
|
// AddTotal adds to the total number of work units. This is used to calculate the
|
|
// progress percentage.
|
|
func (p *Progress) AddTotal(total int) {
|
|
p.mutex.Lock()
|
|
defer p.mutex.Unlock()
|
|
|
|
p.total += total
|
|
p.calculatePercent()
|
|
}
|
|
|
|
// SetProcessed sets the number of work units completed. This is used to
|
|
// calculate the progress percentage.
|
|
func (p *Progress) SetProcessed(processed int) {
|
|
p.mutex.Lock()
|
|
defer p.mutex.Unlock()
|
|
|
|
p.processed = processed
|
|
p.calculatePercent()
|
|
}
|
|
|
|
func (p *Progress) calculatePercent() {
|
|
switch {
|
|
case !p.defined || p.total <= 0:
|
|
p.percent = ProgressIndefinite
|
|
case p.processed < 0:
|
|
p.percent = 0
|
|
default:
|
|
p.percent = float64(p.processed) / float64(p.total)
|
|
if p.percent > 1 {
|
|
p.percent = 1
|
|
}
|
|
}
|
|
|
|
p.updated()
|
|
}
|
|
|
|
// SetPercent sets the progress percent directly. This value will be
|
|
// overwritten if Indefinite, SetTotal, Increment or SetProcessed is called.
|
|
// Constrains the percent value between 0 and 1, inclusive.
|
|
func (p *Progress) SetPercent(percent float64) {
|
|
p.mutex.Lock()
|
|
defer p.mutex.Unlock()
|
|
|
|
if percent < 0 {
|
|
percent = 0
|
|
} else if percent > 1 {
|
|
percent = 1
|
|
}
|
|
|
|
p.percent = percent
|
|
p.updated()
|
|
}
|
|
|
|
// Increment increments the number of processed work units. This is used to calculate the percentage.
|
|
// If total is set already, then the number of processed work units will not exceed the total.
|
|
func (p *Progress) Increment() {
|
|
p.mutex.Lock()
|
|
defer p.mutex.Unlock()
|
|
|
|
if !p.defined || p.total <= 0 || p.processed < p.total {
|
|
p.processed++
|
|
p.calculatePercent()
|
|
}
|
|
}
|
|
|
|
// AddProcessed increments the number of processed work units by the provided
|
|
// amount. This is used to calculate the percentage.
|
|
func (p *Progress) AddProcessed(v int) {
|
|
p.mutex.Lock()
|
|
defer p.mutex.Unlock()
|
|
|
|
newVal := v
|
|
if p.defined && p.total > 0 && newVal > p.total {
|
|
newVal = p.total
|
|
}
|
|
|
|
p.processed = newVal
|
|
p.calculatePercent()
|
|
}
|
|
|
|
func (p *Progress) addTask(t *task) {
|
|
p.mutex.Lock()
|
|
defer p.mutex.Unlock()
|
|
|
|
p.currentTasks = append([]*task{t}, p.currentTasks...)
|
|
p.updated()
|
|
}
|
|
|
|
func (p *Progress) removeTask(t *task) {
|
|
p.mutex.Lock()
|
|
defer p.mutex.Unlock()
|
|
|
|
for i, tt := range p.currentTasks {
|
|
if tt == t {
|
|
p.currentTasks = append(p.currentTasks[:i], p.currentTasks[i+1:]...)
|
|
p.updated()
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
// ExecuteTask executes a task as part of a job. The description is used to
|
|
// populate the Details slice in the parent Job.
|
|
func (p *Progress) ExecuteTask(description string, fn func()) {
|
|
t := &task{
|
|
description: description,
|
|
}
|
|
|
|
p.addTask(t)
|
|
defer p.removeTask(t)
|
|
fn()
|
|
}
|