mirror of
https://github.com/sbondCo/Watcharr.git
synced 2026-08-07 07:14:44 +00:00
144 lines
4.2 KiB
Go
144 lines
4.2 KiB
Go
// We will use jobs only for storing/retrieving active job statuses for the client.
|
|
// Running the job will be done wherever needed, but isn't handled here.
|
|
// When starting a job elsewhere, we should first add a job here as active to get an `id`,
|
|
// this id should be used to update the active job so the client can request job status updates.
|
|
|
|
package main
|
|
|
|
import (
|
|
"errors"
|
|
"log/slog"
|
|
"time"
|
|
)
|
|
|
|
type JobStatus string
|
|
|
|
var (
|
|
JOB_CREATED JobStatus = "CREATED"
|
|
JOB_RUNNING JobStatus = "RUNNING"
|
|
JOB_DONE JobStatus = "DONE"
|
|
JOB_CANCELLED JobStatus = "CANCELLED"
|
|
)
|
|
|
|
type Job struct {
|
|
// We can give the job a name simply for showing on the client.
|
|
Name string `json:"name"`
|
|
// The current status of the job.
|
|
Status JobStatus `json:"status"`
|
|
// The current task we are performing inside the job.
|
|
// Just so we can portray progress on the client by displaying the current task.
|
|
CurrentTask string `json:"currentTask,omitempty"`
|
|
// Errors that occurred in the task
|
|
Errors []string `json:"errors"`
|
|
// Stored for access control.
|
|
UserId uint `json:"-"`
|
|
}
|
|
|
|
var activeJobs = make(map[string]*Job)
|
|
|
|
// Add a job to our activeJobs map.
|
|
// Returns id of job on success, or error if failed to add.
|
|
// Only return safe errors for display to users, log serious errors.
|
|
func addJob(name string, userId uint) (string, error) {
|
|
idk, err := generateString(8)
|
|
if err != nil {
|
|
slog.Error("addJob: Failed to generate a job id!", "error", err)
|
|
return "", errors.New("failed to generate a job id, please try again")
|
|
}
|
|
_, ok := activeJobs[idk]
|
|
if ok {
|
|
// Lets just hope this doesn't happen, may the odds be with us.
|
|
return "", errors.New("job already exists with id generated, please try again")
|
|
}
|
|
activeJobs[idk] = &Job{
|
|
Name: name,
|
|
Status: JOB_CREATED,
|
|
UserId: userId,
|
|
}
|
|
return idk, nil
|
|
}
|
|
|
|
// Add a job, but only if one with the same `name` isn't already running.
|
|
// Only return safe errors for display to users.
|
|
func addUniqueJob(name string, userId uint) (string, error) {
|
|
found := false
|
|
for _, v := range activeJobs {
|
|
if v.UserId == userId && v.Name == name && (v.Status == JOB_CREATED || v.Status == JOB_RUNNING) {
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
if found {
|
|
return "", errors.New("a job of this type is already running, please wait for the existing job to finish")
|
|
}
|
|
return addJob(name, userId)
|
|
}
|
|
|
|
func rmJob(id string, userId uint) {
|
|
slog.Debug("rmJob: Removing a job.", "id", id)
|
|
v, ok := activeJobs[id]
|
|
if ok && v.UserId == userId {
|
|
delete(activeJobs, id)
|
|
slog.Debug("rmJob: Removed a job.", "id", id)
|
|
return
|
|
}
|
|
slog.Debug("rmJob: Job to remove does not exist (or not owned by this user).", "id", id, "user_id", userId)
|
|
}
|
|
|
|
// Get a job.
|
|
// Returns job if found, otherwise errors if job does not exist.
|
|
func getJob(id string, userId uint) (*Job, error) {
|
|
j, ok := activeJobs[id]
|
|
if ok {
|
|
// Ensure user requesting a job, owns the job.
|
|
if j.UserId != userId {
|
|
slog.Warn("getJob: A user tried to access a job they do not own.", "user_id", userId, "job_id", id)
|
|
return &Job{}, errors.New("job does not exist")
|
|
}
|
|
return j, nil
|
|
}
|
|
return &Job{}, errors.New("job does not exist")
|
|
}
|
|
|
|
// Update a jobs status.
|
|
func updateJobStatus(id string, userId uint, status JobStatus) error {
|
|
j, err := getJob(id, userId)
|
|
if err != nil {
|
|
slog.Error("updateJobStatus: Failed!", "status", status, "error", err)
|
|
return err
|
|
}
|
|
j.Status = status
|
|
// If job is set to done, remove it after 1 minute.
|
|
if status == JOB_DONE || status == JOB_CANCELLED {
|
|
slog.Debug("updateJobStatus: Job set to done or cancelled. Will be removed after 30m.", "id", id, "status", status)
|
|
go func() {
|
|
time.Sleep(30 * time.Minute)
|
|
slog.Debug("updateJobStatus: Job done. waited 30m.. removing job now.", "id", id)
|
|
rmJob(id, userId)
|
|
}()
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Update a jobs current task.
|
|
func updateJobCurrentTask(id string, userId uint, ct string) error {
|
|
j, err := getJob(id, userId)
|
|
if err != nil {
|
|
slog.Error("updateJobCurrentTask: Failed!", "ct", ct, "error", err)
|
|
return err
|
|
}
|
|
j.CurrentTask = ct
|
|
return nil
|
|
}
|
|
|
|
// Add an error to a job.
|
|
func addJobError(id string, userId uint, e string) error {
|
|
j, err := getJob(id, userId)
|
|
if err != nil {
|
|
slog.Error("updateJobCurrentTask: Failed!", "e", e, "error", err)
|
|
return err
|
|
}
|
|
j.Errors = append(j.Errors, e)
|
|
return nil
|
|
}
|