2023-05-20 22:10:24 +02:00
|
|
|
|
using Logging;
|
|
|
|
|
using Newtonsoft.Json;
|
2023-05-19 16:23:37 +02:00
|
|
|
|
using Tranga.Connectors;
|
2023-05-31 21:15:32 +02:00
|
|
|
|
using Tranga.TrangaTasks;
|
2023-05-19 14:15:00 +02:00
|
|
|
|
|
|
|
|
|
namespace Tranga;
|
2023-05-17 23:23:01 +02:00
|
|
|
|
|
2023-05-19 20:03:17 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Manages all TrangaTasks.
|
|
|
|
|
/// Provides a Threaded environment to execute Tasks, and still manage the Task-Collection
|
|
|
|
|
/// </summary>
|
2023-05-17 23:23:01 +02:00
|
|
|
|
public class TaskManager
|
|
|
|
|
{
|
2023-05-31 21:18:41 +02:00
|
|
|
|
public Dictionary<Publication, List<Chapter>> chapterCollection = new();
|
2023-06-07 00:24:58 +02:00
|
|
|
|
private HashSet<TrangaTask> _allTasks = new();
|
2023-06-27 22:58:40 +02:00
|
|
|
|
private readonly Dictionary<TrangaTask, CancellationTokenSource> _runningTasks = new ();
|
2023-05-17 23:23:01 +02:00
|
|
|
|
private bool _continueRunning = true;
|
2023-05-20 01:06:00 +02:00
|
|
|
|
private readonly Connector[] _connectors;
|
2023-05-22 00:13:24 +02:00
|
|
|
|
public TrangaSettings settings { get; }
|
2023-05-20 22:10:24 +02:00
|
|
|
|
private Logger? logger { get; }
|
2023-05-19 16:27:56 +02:00
|
|
|
|
|
2023-06-15 17:06:41 +02:00
|
|
|
|
public TaskManager(TrangaSettings settings, Logger? logger = null)
|
|
|
|
|
{
|
|
|
|
|
this.logger = logger;
|
2023-06-01 13:13:53 +02:00
|
|
|
|
this._connectors = new Connector[]
|
|
|
|
|
{
|
2023-06-27 22:57:44 +02:00
|
|
|
|
new MangaDex(settings, logger),
|
|
|
|
|
new Manganato(settings, logger),
|
|
|
|
|
new Mangasee(settings, logger),
|
|
|
|
|
new MangaKatana(settings, logger)
|
2023-06-01 13:13:53 +02:00
|
|
|
|
};
|
2023-05-20 12:53:19 +02:00
|
|
|
|
|
2023-06-15 17:06:41 +02:00
|
|
|
|
this.settings = settings;
|
|
|
|
|
ImportData();
|
|
|
|
|
ExportDataAndSettings();
|
2023-05-20 12:53:19 +02:00
|
|
|
|
Thread taskChecker = new(TaskCheckerThread);
|
|
|
|
|
taskChecker.Start();
|
|
|
|
|
}
|
2023-05-21 22:01:04 +02:00
|
|
|
|
|
2023-05-20 15:05:41 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Runs continuously until shutdown.
|
|
|
|
|
/// Checks if tasks have to be executed (time elapsed)
|
|
|
|
|
/// </summary>
|
2023-05-17 23:23:01 +02:00
|
|
|
|
private void TaskCheckerThread()
|
|
|
|
|
{
|
2023-05-21 01:57:56 +02:00
|
|
|
|
logger?.WriteLine(this.GetType().ToString(), "Starting TaskCheckerThread.");
|
2023-06-19 22:32:32 +02:00
|
|
|
|
int waitingTasksCount = _allTasks.Count(task => task.state is TrangaTask.ExecutionState.Waiting);
|
2023-05-17 23:23:01 +02:00
|
|
|
|
while (_continueRunning)
|
|
|
|
|
{
|
2023-06-19 22:32:32 +02:00
|
|
|
|
foreach (TrangaTask waitingButExecute in _allTasks.Where(taskQuery =>
|
|
|
|
|
taskQuery.nextExecution < DateTime.Now &&
|
|
|
|
|
taskQuery.state is TrangaTask.ExecutionState.Waiting))
|
|
|
|
|
{
|
|
|
|
|
waitingButExecute.state = TrangaTask.ExecutionState.Enqueued;
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-20 14:57:44 +02:00
|
|
|
|
foreach (TrangaTask enqueuedTask in _allTasks.Where(enqueuedTask => enqueuedTask.state is TrangaTask.ExecutionState.Enqueued))
|
2023-05-20 14:50:48 +02:00
|
|
|
|
{
|
2023-06-20 14:57:44 +02:00
|
|
|
|
switch (enqueuedTask.task)
|
2023-05-20 14:50:48 +02:00
|
|
|
|
{
|
2023-06-05 00:35:57 +02:00
|
|
|
|
case TrangaTask.Task.DownloadChapter:
|
2023-06-20 14:57:44 +02:00
|
|
|
|
case TrangaTask.Task.MonitorPublication:
|
2023-06-05 00:35:57 +02:00
|
|
|
|
if (!_allTasks.Any(taskQuery =>
|
2023-06-20 14:57:44 +02:00
|
|
|
|
{
|
|
|
|
|
if (taskQuery.state is not TrangaTask.ExecutionState.Running) return false;
|
|
|
|
|
switch (taskQuery)
|
|
|
|
|
{
|
|
|
|
|
case DownloadChapterTask dct when enqueuedTask is DownloadChapterTask eDct && dct.connectorName == eDct.connectorName:
|
|
|
|
|
case MonitorPublicationTask mpt when enqueuedTask is MonitorPublicationTask eMpt && mpt.connectorName == eMpt.connectorName:
|
|
|
|
|
return true;
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}))
|
2023-06-05 00:35:57 +02:00
|
|
|
|
{
|
2023-06-20 14:57:44 +02:00
|
|
|
|
ExecuteTaskNow(enqueuedTask);
|
2023-06-05 00:35:57 +02:00
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case TrangaTask.Task.UpdateLibraries:
|
2023-06-20 14:57:44 +02:00
|
|
|
|
ExecuteTaskNow(enqueuedTask);
|
2023-06-05 00:35:57 +02:00
|
|
|
|
break;
|
2023-05-20 14:50:48 +02:00
|
|
|
|
}
|
2023-05-17 23:23:01 +02:00
|
|
|
|
}
|
2023-06-27 22:19:06 +02:00
|
|
|
|
|
|
|
|
|
foreach (TrangaTask timedOutTask in _allTasks
|
2023-06-27 22:23:53 +02:00
|
|
|
|
.Where(taskQuery => taskQuery.lastChange < DateTime.Now.Subtract(TimeSpan.FromMinutes(3))))
|
2023-06-27 22:19:06 +02:00
|
|
|
|
{
|
2023-06-27 22:58:40 +02:00
|
|
|
|
_runningTasks[timedOutTask].Cancel();
|
2023-06-27 22:19:06 +02:00
|
|
|
|
timedOutTask.state = TrangaTask.ExecutionState.Failed;
|
|
|
|
|
}
|
2023-06-21 16:53:41 +02:00
|
|
|
|
|
2023-06-27 22:58:40 +02:00
|
|
|
|
foreach (TrangaTask failedTask in _allTasks.Where(taskQuery =>
|
|
|
|
|
taskQuery.state is TrangaTask.ExecutionState.Failed).ToArray())
|
2023-06-07 00:24:27 +02:00
|
|
|
|
{
|
2023-06-27 22:58:40 +02:00
|
|
|
|
DeleteTask(failedTask);
|
|
|
|
|
TrangaTask newTask = failedTask.Clone();
|
|
|
|
|
failedTask.parentTask?.AddChildTask(newTask);
|
2023-06-20 15:46:54 +02:00
|
|
|
|
AddTask(newTask);
|
|
|
|
|
}
|
2023-06-07 00:24:27 +02:00
|
|
|
|
|
2023-06-19 22:32:32 +02:00
|
|
|
|
if(waitingTasksCount != _allTasks.Count(task => task.state is TrangaTask.ExecutionState.Waiting))
|
2023-06-05 00:35:57 +02:00
|
|
|
|
ExportDataAndSettings();
|
2023-06-19 22:32:32 +02:00
|
|
|
|
waitingTasksCount = _allTasks.Count(task => task.state is TrangaTask.ExecutionState.Waiting);
|
2023-05-17 23:23:01 +02:00
|
|
|
|
Thread.Sleep(1000);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-19 20:03:17 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Forces the execution of a given task
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="task">Task to execute</param>
|
2023-05-19 19:20:44 +02:00
|
|
|
|
public void ExecuteTaskNow(TrangaTask task)
|
|
|
|
|
{
|
2023-06-05 00:35:57 +02:00
|
|
|
|
task.state = TrangaTask.ExecutionState.Running;
|
2023-06-10 14:34:30 +02:00
|
|
|
|
CancellationTokenSource cToken = new ();
|
2023-05-31 21:15:32 +02:00
|
|
|
|
Task t = new(() =>
|
2023-05-19 19:20:44 +02:00
|
|
|
|
{
|
2023-06-10 14:34:30 +02:00
|
|
|
|
task.Execute(this, this.logger, cToken.Token);
|
|
|
|
|
}, cToken.Token);
|
2023-06-27 22:58:40 +02:00
|
|
|
|
_runningTasks.Add(task, cToken);
|
2023-05-19 19:20:44 +02:00
|
|
|
|
t.Start();
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-05 00:35:57 +02:00
|
|
|
|
public void AddTask(TrangaTask newTask)
|
2023-05-19 14:15:17 +02:00
|
|
|
|
{
|
2023-06-05 00:35:57 +02:00
|
|
|
|
switch (newTask.task)
|
2023-05-20 14:07:38 +02:00
|
|
|
|
{
|
2023-06-05 00:35:57 +02:00
|
|
|
|
case TrangaTask.Task.UpdateLibraries:
|
|
|
|
|
//Only one UpdateKomgaLibrary Task
|
2023-06-15 22:32:55 +02:00
|
|
|
|
logger?.WriteLine(this.GetType().ToString(), $"Replacing old {newTask.task}-Task.");
|
2023-06-27 22:59:23 +02:00
|
|
|
|
if (GetTasksMatching(newTask).FirstOrDefault() is { } exists)
|
|
|
|
|
_allTasks.Remove(exists);
|
2023-06-15 22:32:55 +02:00
|
|
|
|
_allTasks.Add(newTask);
|
2023-06-27 22:59:23 +02:00
|
|
|
|
ExportDataAndSettings();
|
2023-06-05 00:35:57 +02:00
|
|
|
|
break;
|
2023-06-27 22:59:23 +02:00
|
|
|
|
default:
|
|
|
|
|
if (!GetTasksMatching(newTask).Any())
|
|
|
|
|
{
|
|
|
|
|
logger?.WriteLine(this.GetType().ToString(), $"Adding new Task {newTask}");
|
2023-06-05 00:35:57 +02:00
|
|
|
|
_allTasks.Add(newTask);
|
2023-06-27 22:59:23 +02:00
|
|
|
|
ExportDataAndSettings();
|
|
|
|
|
}
|
2023-06-05 00:35:57 +02:00
|
|
|
|
else
|
|
|
|
|
logger?.WriteLine(this.GetType().ToString(), $"Task already exists {newTask}");
|
|
|
|
|
break;
|
2023-05-20 14:07:38 +02:00
|
|
|
|
}
|
2023-06-05 00:35:57 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void DeleteTask(TrangaTask removeTask)
|
|
|
|
|
{
|
|
|
|
|
logger?.WriteLine(this.GetType().ToString(), $"Removing Task {removeTask}");
|
2023-06-27 22:58:40 +02:00
|
|
|
|
if(_allTasks.Contains(removeTask))
|
|
|
|
|
_allTasks.Remove(removeTask);
|
2023-06-20 14:57:44 +02:00
|
|
|
|
removeTask.parentTask?.RemoveChildTask(removeTask);
|
2023-06-27 22:58:40 +02:00
|
|
|
|
if (_runningTasks.ContainsKey(removeTask))
|
2023-06-11 19:16:05 +02:00
|
|
|
|
{
|
2023-06-27 22:58:40 +02:00
|
|
|
|
_runningTasks[removeTask].Cancel();
|
|
|
|
|
_runningTasks.Remove(removeTask);
|
2023-06-11 19:16:05 +02:00
|
|
|
|
}
|
2023-06-21 16:53:41 +02:00
|
|
|
|
foreach(TrangaTask childTask in removeTask.childTasks)
|
|
|
|
|
DeleteTask(childTask);
|
2023-06-27 23:54:44 +02:00
|
|
|
|
ExportDataAndSettings();
|
2023-06-05 00:35:57 +02:00
|
|
|
|
}
|
2023-05-31 21:14:11 +02:00
|
|
|
|
|
2023-06-27 22:59:23 +02:00
|
|
|
|
public IEnumerable<TrangaTask> GetTasksMatching(TrangaTask mTask)
|
|
|
|
|
{
|
|
|
|
|
switch (mTask.task)
|
|
|
|
|
{
|
|
|
|
|
case TrangaTask.Task.UpdateLibraries:
|
|
|
|
|
return GetTasksMatching(TrangaTask.Task.UpdateLibraries);
|
|
|
|
|
case TrangaTask.Task.DownloadChapter:
|
|
|
|
|
DownloadChapterTask dct = (DownloadChapterTask)mTask;
|
|
|
|
|
return GetTasksMatching(TrangaTask.Task.DownloadChapter, connectorName: dct.connectorName,
|
|
|
|
|
internalId: dct.publication.internalId);
|
|
|
|
|
case TrangaTask.Task.MonitorPublication:
|
|
|
|
|
MonitorPublicationTask mpt = (MonitorPublicationTask)mTask;
|
|
|
|
|
return GetTasksMatching(TrangaTask.Task.MonitorPublication, connectorName: mpt.connectorName,
|
|
|
|
|
internalId: mpt.publication.internalId);
|
|
|
|
|
}
|
|
|
|
|
return Array.Empty<TrangaTask>();
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-27 23:06:37 +02:00
|
|
|
|
public IEnumerable<TrangaTask> GetTasksMatching(TrangaTask.Task taskType, string? connectorName = null, string? searchString = null, string? internalId = null, string? chapterNumber = null)
|
2023-06-05 00:35:57 +02:00
|
|
|
|
{
|
|
|
|
|
switch (taskType)
|
2023-05-21 01:57:56 +02:00
|
|
|
|
{
|
2023-06-05 00:35:57 +02:00
|
|
|
|
case TrangaTask.Task.UpdateLibraries:
|
|
|
|
|
return _allTasks.Where(tTask => tTask.task == TrangaTask.Task.UpdateLibraries);
|
2023-06-20 14:57:44 +02:00
|
|
|
|
case TrangaTask.Task.MonitorPublication:
|
2023-06-05 00:35:57 +02:00
|
|
|
|
if(connectorName is null)
|
|
|
|
|
return _allTasks.Where(tTask => tTask.task == taskType);
|
|
|
|
|
GetConnector(connectorName);//Name check
|
|
|
|
|
if (searchString is not null)
|
|
|
|
|
{
|
2023-06-20 14:57:44 +02:00
|
|
|
|
return _allTasks.Where(mTask =>
|
|
|
|
|
mTask is MonitorPublicationTask mpt && mpt.connectorName == connectorName &&
|
|
|
|
|
mpt.ToString().Contains(searchString, StringComparison.InvariantCultureIgnoreCase));
|
2023-06-05 00:35:57 +02:00
|
|
|
|
}
|
2023-06-05 00:50:51 +02:00
|
|
|
|
else if (internalId is not null)
|
2023-06-05 00:35:57 +02:00
|
|
|
|
{
|
2023-06-20 14:57:44 +02:00
|
|
|
|
return _allTasks.Where(mTask =>
|
|
|
|
|
mTask is MonitorPublicationTask mpt && mpt.connectorName == connectorName &&
|
2023-06-25 23:56:00 +02:00
|
|
|
|
mpt.publication.internalId == internalId);
|
2023-06-05 00:35:57 +02:00
|
|
|
|
}
|
2023-05-22 17:04:31 +02:00
|
|
|
|
else
|
2023-06-05 00:35:57 +02:00
|
|
|
|
return _allTasks.Where(tTask =>
|
2023-06-20 14:57:44 +02:00
|
|
|
|
tTask is MonitorPublicationTask mpt && mpt.connectorName == connectorName);
|
2023-06-05 00:35:57 +02:00
|
|
|
|
|
|
|
|
|
case TrangaTask.Task.DownloadChapter:
|
|
|
|
|
if(connectorName is null)
|
|
|
|
|
return _allTasks.Where(tTask => tTask.task == taskType);
|
|
|
|
|
GetConnector(connectorName);//Name check
|
|
|
|
|
if (searchString is not null)
|
|
|
|
|
{
|
2023-06-20 14:57:44 +02:00
|
|
|
|
return _allTasks.Where(mTask =>
|
|
|
|
|
mTask is DownloadChapterTask dct && dct.connectorName == connectorName &&
|
|
|
|
|
dct.ToString().Contains(searchString, StringComparison.InvariantCultureIgnoreCase));
|
2023-06-05 00:35:57 +02:00
|
|
|
|
}
|
2023-06-27 23:06:37 +02:00
|
|
|
|
else if (internalId is not null && chapterNumber is not null)
|
2023-06-05 00:35:57 +02:00
|
|
|
|
{
|
2023-06-20 14:57:44 +02:00
|
|
|
|
return _allTasks.Where(mTask =>
|
|
|
|
|
mTask is DownloadChapterTask dct && dct.connectorName == connectorName &&
|
2023-06-25 23:56:00 +02:00
|
|
|
|
dct.publication.internalId == internalId &&
|
2023-06-27 23:06:37 +02:00
|
|
|
|
dct.chapter.chapterNumber == chapterNumber);
|
2023-06-05 00:35:57 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
2023-06-20 14:57:44 +02:00
|
|
|
|
return _allTasks.Where(mTask =>
|
|
|
|
|
mTask is DownloadChapterTask dct && dct.connectorName == connectorName);
|
2023-06-05 00:35:57 +02:00
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return Array.Empty<TrangaTask>();
|
2023-05-21 01:57:56 +02:00
|
|
|
|
}
|
2023-05-19 14:15:17 +02:00
|
|
|
|
}
|
2023-05-21 03:04:32 +02:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Removes a Task from the queue
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="task"></param>
|
|
|
|
|
public void RemoveTaskFromQueue(TrangaTask task)
|
|
|
|
|
{
|
|
|
|
|
task.lastExecuted = DateTime.Now;
|
|
|
|
|
task.state = TrangaTask.ExecutionState.Waiting;
|
|
|
|
|
}
|
2023-05-21 03:18:56 +02:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Sets last execution time to start of time
|
|
|
|
|
/// Let taskManager handle enqueuing
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="task"></param>
|
|
|
|
|
public void AddTaskToQueue(TrangaTask task)
|
|
|
|
|
{
|
|
|
|
|
task.lastExecuted = DateTime.UnixEpoch;
|
|
|
|
|
}
|
2023-05-20 12:53:19 +02:00
|
|
|
|
|
2023-05-19 20:03:17 +02:00
|
|
|
|
/// <returns>All available Connectors</returns>
|
2023-05-19 16:27:56 +02:00
|
|
|
|
public Dictionary<string, Connector> GetAvailableConnectors()
|
|
|
|
|
{
|
2023-05-20 01:06:00 +02:00
|
|
|
|
return this._connectors.ToDictionary(connector => connector.name, connector => connector);
|
2023-05-19 16:27:56 +02:00
|
|
|
|
}
|
2023-05-20 12:53:19 +02:00
|
|
|
|
|
2023-05-19 20:03:17 +02:00
|
|
|
|
/// <returns>All TrangaTasks in task-collection</returns>
|
2023-05-19 16:27:56 +02:00
|
|
|
|
public TrangaTask[] GetAllTasks()
|
|
|
|
|
{
|
|
|
|
|
TrangaTask[] ret = new TrangaTask[_allTasks.Count];
|
|
|
|
|
_allTasks.CopyTo(ret);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
2023-05-21 21:12:32 +02:00
|
|
|
|
|
|
|
|
|
public Publication[] GetPublicationsFromConnector(Connector connector, string? title = null)
|
|
|
|
|
{
|
|
|
|
|
Publication[] ret = connector.GetPublications(title ?? "");
|
2023-05-21 21:23:51 +02:00
|
|
|
|
foreach (Publication publication in ret)
|
|
|
|
|
{
|
2023-06-05 00:35:57 +02:00
|
|
|
|
if(chapterCollection.All(pub => pub.Key.internalId != publication.internalId))
|
2023-05-31 21:18:41 +02:00
|
|
|
|
this.chapterCollection.TryAdd(publication, new List<Chapter>());
|
2023-05-21 21:23:51 +02:00
|
|
|
|
}
|
2023-05-21 21:12:32 +02:00
|
|
|
|
return ret;
|
|
|
|
|
}
|
2023-05-20 12:53:19 +02:00
|
|
|
|
|
2023-05-19 20:03:17 +02:00
|
|
|
|
/// <returns>All added Publications</returns>
|
2023-05-19 17:36:15 +02:00
|
|
|
|
public Publication[] GetAllPublications()
|
|
|
|
|
{
|
2023-05-31 21:18:41 +02:00
|
|
|
|
return this.chapterCollection.Keys.ToArray();
|
2023-05-19 17:36:15 +02:00
|
|
|
|
}
|
2023-06-15 17:07:32 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Updates the available Chapters of a Publication
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="connector">Connector to use</param>
|
|
|
|
|
/// <param name="publication">Publication to check</param>
|
|
|
|
|
/// <param name="language">Language to receive chapters for</param>
|
|
|
|
|
/// <returns>List of Chapters that were previously not in collection</returns>
|
|
|
|
|
public List<Chapter> GetNewChaptersList(Connector connector, Publication publication, string language)
|
|
|
|
|
{
|
|
|
|
|
List<Chapter> newChaptersList = new();
|
|
|
|
|
chapterCollection.TryAdd(publication, newChaptersList); //To ensure publication is actually in collection
|
|
|
|
|
|
|
|
|
|
Chapter[] newChapters = connector.GetChapters(publication, language);
|
2023-06-27 23:22:23 +02:00
|
|
|
|
newChaptersList = newChapters.Where(nChapter => !nChapter.CheckChapterIsDownloaded(settings.downloadLocation)).ToList();
|
2023-06-15 17:07:32 +02:00
|
|
|
|
|
|
|
|
|
return newChaptersList;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public List<Chapter> GetExistingChaptersList(Connector connector, Publication publication, string language)
|
|
|
|
|
{
|
|
|
|
|
Chapter[] newChapters = connector.GetChapters(publication, language);
|
2023-06-27 23:22:23 +02:00
|
|
|
|
return newChapters.Where(nChapter => nChapter.CheckChapterIsDownloaded(settings.downloadLocation)).ToList();
|
2023-06-15 17:07:32 +02:00
|
|
|
|
}
|
2023-05-20 14:07:38 +02:00
|
|
|
|
|
2023-05-20 15:05:41 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Return Connector with given Name
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="connectorName">Connector-name (exact)</param>
|
|
|
|
|
/// <exception cref="Exception">If Connector is not available</exception>
|
2023-05-21 02:13:19 +02:00
|
|
|
|
public Connector GetConnector(string? connectorName)
|
2023-05-20 14:07:38 +02:00
|
|
|
|
{
|
2023-05-20 17:18:22 +02:00
|
|
|
|
if(connectorName is null)
|
|
|
|
|
throw new Exception($"connectorName can not be null");
|
2023-05-20 14:18:03 +02:00
|
|
|
|
Connector? ret = this._connectors.FirstOrDefault(connector => connector.name == connectorName);
|
|
|
|
|
if (ret is null)
|
|
|
|
|
throw new Exception($"Connector {connectorName} is not an available Connector.");
|
2023-05-31 21:18:41 +02:00
|
|
|
|
return ret;
|
2023-05-20 14:07:38 +02:00
|
|
|
|
}
|
2023-05-19 16:27:56 +02:00
|
|
|
|
|
2023-05-19 20:03:17 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Shuts down the taskManager.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="force">If force is true, tasks are aborted.</param>
|
2023-05-19 19:21:54 +02:00
|
|
|
|
public void Shutdown(bool force = false)
|
2023-05-17 23:23:01 +02:00
|
|
|
|
{
|
2023-05-20 22:10:24 +02:00
|
|
|
|
logger?.WriteLine(this.GetType().ToString(), $"Shutting down (forced={force})");
|
2023-05-17 23:23:01 +02:00
|
|
|
|
_continueRunning = false;
|
2023-05-31 21:14:11 +02:00
|
|
|
|
ExportDataAndSettings();
|
2023-05-19 19:21:54 +02:00
|
|
|
|
|
|
|
|
|
if(force)
|
2023-05-20 14:50:48 +02:00
|
|
|
|
Environment.Exit(_allTasks.Count(task => task.state is TrangaTask.ExecutionState.Enqueued or TrangaTask.ExecutionState.Running));
|
2023-05-19 19:21:54 +02:00
|
|
|
|
|
|
|
|
|
//Wait for tasks to finish
|
2023-05-20 14:50:48 +02:00
|
|
|
|
while(_allTasks.Any(task => task.state is TrangaTask.ExecutionState.Running or TrangaTask.ExecutionState.Enqueued))
|
2023-05-19 19:21:54 +02:00
|
|
|
|
Thread.Sleep(10);
|
2023-05-21 01:57:56 +02:00
|
|
|
|
logger?.WriteLine(this.GetType().ToString(), "Tasks finished. Bye!");
|
2023-05-19 20:22:13 +02:00
|
|
|
|
Environment.Exit(0);
|
2023-05-19 13:59:26 +02:00
|
|
|
|
}
|
|
|
|
|
|
2023-05-22 00:13:24 +02:00
|
|
|
|
private void ImportData()
|
2023-05-19 13:59:26 +02:00
|
|
|
|
{
|
2023-05-22 00:13:24 +02:00
|
|
|
|
logger?.WriteLine(this.GetType().ToString(), "Importing Data");
|
|
|
|
|
string buffer;
|
|
|
|
|
if (File.Exists(settings.tasksFilePath))
|
|
|
|
|
{
|
|
|
|
|
logger?.WriteLine(this.GetType().ToString(), $"Importing tasks from {settings.tasksFilePath}");
|
|
|
|
|
buffer = File.ReadAllText(settings.tasksFilePath);
|
2023-05-31 21:43:07 +02:00
|
|
|
|
this._allTasks = JsonConvert.DeserializeObject<HashSet<TrangaTask>>(buffer, new JsonSerializerSettings() { Converters = { new TrangaTask.TrangaTaskJsonConverter() } })!;
|
2023-05-22 00:13:24 +02:00
|
|
|
|
}
|
2023-05-19 16:23:37 +02:00
|
|
|
|
|
2023-06-24 21:00:26 +02:00
|
|
|
|
foreach (TrangaTask task in this._allTasks.Where(tTask => tTask.parentTaskId is not null).ToArray())
|
2023-06-10 15:59:23 +02:00
|
|
|
|
{
|
2023-06-11 18:24:26 +02:00
|
|
|
|
TrangaTask? parentTask = this._allTasks.FirstOrDefault(pTask => pTask.taskId == task.parentTaskId);
|
|
|
|
|
if (parentTask is not null)
|
|
|
|
|
{
|
2023-06-24 21:00:26 +02:00
|
|
|
|
this.DeleteTask(task);
|
|
|
|
|
parentTask.lastExecuted = DateTime.UnixEpoch;
|
2023-06-11 18:24:26 +02:00
|
|
|
|
}
|
2023-06-10 15:59:23 +02:00
|
|
|
|
}
|
2023-06-24 21:00:26 +02:00
|
|
|
|
|
2023-05-22 00:13:24 +02:00
|
|
|
|
if (File.Exists(settings.knownPublicationsPath))
|
|
|
|
|
{
|
|
|
|
|
logger?.WriteLine(this.GetType().ToString(), $"Importing known publications from {settings.knownPublicationsPath}");
|
|
|
|
|
buffer = File.ReadAllText(settings.knownPublicationsPath);
|
|
|
|
|
Publication[] publications = JsonConvert.DeserializeObject<Publication[]>(buffer)!;
|
|
|
|
|
foreach (Publication publication in publications)
|
2023-05-31 21:18:41 +02:00
|
|
|
|
this.chapterCollection.TryAdd(publication, new List<Chapter>());
|
2023-05-22 00:13:24 +02:00
|
|
|
|
}
|
2023-05-19 13:59:26 +02:00
|
|
|
|
}
|
|
|
|
|
|
2023-05-20 15:05:41 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Exports data (settings, tasks) to file
|
|
|
|
|
/// </summary>
|
2023-05-31 21:14:11 +02:00
|
|
|
|
private void ExportDataAndSettings()
|
2023-05-19 13:59:26 +02:00
|
|
|
|
{
|
2023-05-22 00:13:24 +02:00
|
|
|
|
logger?.WriteLine(this.GetType().ToString(), $"Exporting settings to {settings.settingsFilePath}");
|
2023-06-21 18:04:12 +02:00
|
|
|
|
settings.ExportSettings();
|
2023-05-21 21:12:32 +02:00
|
|
|
|
|
2023-05-22 00:13:24 +02:00
|
|
|
|
logger?.WriteLine(this.GetType().ToString(), $"Exporting tasks to {settings.tasksFilePath}");
|
2023-06-05 00:35:57 +02:00
|
|
|
|
while(IsFileInUse(settings.tasksFilePath))
|
|
|
|
|
Thread.Sleep(50);
|
2023-05-22 00:13:24 +02:00
|
|
|
|
File.WriteAllText(settings.tasksFilePath, JsonConvert.SerializeObject(this._allTasks));
|
2023-05-21 21:12:32 +02:00
|
|
|
|
|
2023-05-22 00:13:24 +02:00
|
|
|
|
logger?.WriteLine(this.GetType().ToString(), $"Exporting known publications to {settings.knownPublicationsPath}");
|
2023-06-05 00:35:57 +02:00
|
|
|
|
while(IsFileInUse(settings.knownPublicationsPath))
|
|
|
|
|
Thread.Sleep(50);
|
2023-05-31 21:18:41 +02:00
|
|
|
|
File.WriteAllText(settings.knownPublicationsPath, JsonConvert.SerializeObject(this.chapterCollection.Keys.ToArray()));
|
2023-05-20 12:53:19 +02:00
|
|
|
|
}
|
|
|
|
|
|
2023-06-05 00:35:57 +02:00
|
|
|
|
private bool IsFileInUse(string path)
|
|
|
|
|
{
|
|
|
|
|
if (!File.Exists(path))
|
|
|
|
|
return false;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
using FileStream stream = new (path, FileMode.Open, FileAccess.Read, FileShare.None);
|
|
|
|
|
stream.Close();
|
|
|
|
|
}
|
|
|
|
|
catch (IOException)
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2023-05-17 23:23:01 +02:00
|
|
|
|
}
|