Added Jobs and ProgressToken

This commit is contained in:
2023-08-04 14:51:40 +02:00
parent e4086a8892
commit a4aa571870
11 changed files with 284 additions and 49 deletions

View File

@ -0,0 +1,23 @@
using Tranga.MangaConnectors;
namespace Tranga.Jobs;
public class DownloadChapter : Job
{
public Chapter chapter { get; init; }
public DownloadChapter(MangaConnector connector, Chapter chapter) : base(connector)
{
this.chapter = chapter;
}
protected override IEnumerable<Job> ExecuteReturnSubTasksInternal()
{
Task downloadTask = new(delegate
{
mangaConnector.DownloadChapter(chapter, this.progressToken);
});
downloadTask.Start();
return Array.Empty<Job>();
}
}

View File

@ -0,0 +1,27 @@
using Tranga.MangaConnectors;
namespace Tranga.Jobs;
public class DownloadNewChapters : Job
{
public Publication publication { get; init; }
public DownloadNewChapters(MangaConnector connector, Publication publication, bool recurring = false) : base (connector, recurring)
{
this.publication = publication;
}
protected override IEnumerable<Job> ExecuteReturnSubTasksInternal()
{
Chapter[] chapters = mangaConnector.GetNewChapters(publication);
this.progressToken.increments = chapters.Length;
List<Job> subJobs = new();
foreach (Chapter chapter in chapters)
{
DownloadChapter downloadChapterJob = new(this.mangaConnector, chapter);
subJobs.Add(downloadChapterJob);
}
progressToken.Complete();
return subJobs;
}
}

73
Tranga/Jobs/Job.cs Normal file
View File

@ -0,0 +1,73 @@
using Tranga.MangaConnectors;
namespace Tranga.Jobs;
public abstract class Job
{
public MangaConnector mangaConnector { get; init; }
public ProgressToken progressToken { get; private set; }
public bool recurring { get; init; }
public TimeSpan? recurrenceTime { get; set; }
public DateTime? lastExecution { get; private set; }
public DateTime nextExecution => NextExecution();
public Job(MangaConnector connector, bool recurring = false, TimeSpan? recurrenceTime = null)
{
this.mangaConnector = connector;
this.progressToken = new ProgressToken(0);
this.recurring = recurring;
if (recurring && recurrenceTime is null)
throw new ArgumentException("If recurrence is set to true, a recurrence time has to be provided.");
this.recurrenceTime = recurrenceTime;
}
public Job(MangaConnector connector, ProgressToken progressToken, bool recurring = false, TimeSpan? recurrenceTime = null)
{
this.mangaConnector = connector;
this.progressToken = progressToken;
this.recurring = recurring;
if (recurring && recurrenceTime is null)
throw new ArgumentException("If recurrence is set to true, a recurrence time has to be provided.");
this.recurrenceTime = recurrenceTime;
}
public Job(MangaConnector connector, int taskIncrements, bool recurring = false, TimeSpan? recurrenceTime = null)
{
this.mangaConnector = connector;
this.progressToken = new ProgressToken(taskIncrements);
this.recurring = recurring;
if (recurring && recurrenceTime is null)
throw new ArgumentException("If recurrence is set to true, a recurrence time has to be provided.");
this.recurrenceTime = recurrenceTime;
}
private DateTime NextExecution()
{
if(recurring && recurrenceTime.HasValue && lastExecution.HasValue)
return lastExecution.Value.Add(recurrenceTime.Value);
if(recurring && recurrenceTime.HasValue && !lastExecution.HasValue)
return DateTime.Now;
return DateTime.MaxValue;
}
public void Reset()
{
this.progressToken = new ProgressToken(this.progressToken.increments);
}
public void Cancel()
{
this.progressToken.cancellationRequested = true;
this.progressToken.Complete();
}
public IEnumerable<Job> ExecuteReturnSubTasks()
{
progressToken.Start();
IEnumerable<Job> ret = ExecuteReturnSubTasksInternal();
lastExecution = DateTime.Now;
return ret;
}
protected abstract IEnumerable<Job> ExecuteReturnSubTasksInternal();
}

70
Tranga/Jobs/JobBoss.cs Normal file
View File

@ -0,0 +1,70 @@
using System.Runtime.CompilerServices;
using Tranga.MangaConnectors;
namespace Tranga.Jobs;
public class JobBoss : GlobalBase
{
private HashSet<Job> jobs { get; init; }
private Dictionary<MangaConnector, Queue<Job>> mangaConnectorJobQueue { get; init; }
public JobBoss(GlobalBase clone) : base(clone)
{
this.jobs = new();
this.mangaConnectorJobQueue = new();
}
public void MonitorJobs()
{
foreach (Job job in jobs.Where(job => job.nextExecution < DateTime.Now && !QueueContainsJob(job)).OrderBy(job => job.nextExecution))
AddJobToQueue(job);
CheckJobQueue();
}
public void AddJob(Job job)
{
this.jobs.Add(job);
}
public void RemoveJob(Job job)
{
job.Cancel();
this.jobs.Remove(job);
}
private bool QueueContainsJob(Job job)
{
mangaConnectorJobQueue.TryAdd(job.mangaConnector, new Queue<Job>());
return mangaConnectorJobQueue[job.mangaConnector].Contains(job);
}
private void AddJobToQueue(Job job)
{
Log($"Adding Job to Queue. {job}");
mangaConnectorJobQueue.TryAdd(job.mangaConnector, new Queue<Job>());
Queue<Job> connectorJobQueue = mangaConnectorJobQueue[job.mangaConnector];
if(!connectorJobQueue.Contains(job))
connectorJobQueue.Enqueue(job);
}
public void AddJobsToQueue(IEnumerable<Job> jobs)
{
foreach(Job job in jobs)
AddJobToQueue(job);
}
private void CheckJobQueue()
{
foreach (Queue<Job> jobQueue in mangaConnectorJobQueue.Values)
{
Job queueHead = jobQueue.Peek();
if (queueHead.progressToken.state == ProgressToken.State.Complete)
{
if(queueHead.recurring)
queueHead.Reset();
jobQueue.Dequeue();
AddJobsToQueue(jobQueue.Peek().ExecuteReturnSubTasks());
}
}
}
}

View File

@ -0,0 +1,44 @@
namespace Tranga.Jobs;
public class ProgressToken
{
public bool cancellationRequested { get; set; }
public int increments { get; set; }
public int incrementsCompleted { get; set; }
public float progress => GetProgress();
public enum State { Running, Complete, Standby }
public State state { get; private set; }
public ProgressToken(int increments)
{
this.cancellationRequested = false;
this.increments = increments;
this.incrementsCompleted = 0;
this.state = State.Standby;
}
private float GetProgress()
{
if(increments > 0 && incrementsCompleted > 0)
return (float)incrementsCompleted / (float)increments;
return 0;
}
public void Increment()
{
this.incrementsCompleted++;
if (incrementsCompleted > increments)
state = State.Complete;
}
public void Start()
{
state = State.Running;
}
public void Complete()
{
state = State.Complete;
}
}