2023-05-19 16:23:37 +02:00
using Newtonsoft.Json ;
using Tranga.Connectors ;
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-19 14:00:30 +02:00
private readonly Dictionary < Publication , List < Chapter > > _chapterCollection ;
2023-05-18 19:25:46 +02:00
private readonly HashSet < TrangaTask > _allTasks ;
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-19 16:27:56 +02:00
2023-05-19 20:03:17 +02:00
/// <summary>
///
/// </summary>
/// <param name="folderPath">Local path to save data (Manga) to</param>
2023-05-19 16:27:56 +02:00
public TaskManager ( string folderPath )
2023-05-17 23:23:01 +02:00
{
2023-05-20 01:06:00 +02:00
this . _connectors = new Connector [ ] { new MangaDex ( folderPath ) } ;
2023-05-18 19:25:46 +02:00
_chapterCollection = new ( ) ;
2023-05-19 14:15:00 +02:00
_allTasks = ImportTasks ( Directory . GetCurrentDirectory ( ) ) ;
2023-05-17 23:23:01 +02:00
Thread taskChecker = new ( TaskCheckerThread ) ;
taskChecker . Start ( ) ;
}
private void TaskCheckerThread ( )
{
while ( _continueRunning )
{
2023-05-19 16:27:56 +02:00
foreach ( TrangaTask task in _allTasks )
2023-05-17 23:23:01 +02:00
{
2023-05-19 16:27:56 +02:00
if ( task . ShouldExecute ( ) )
2023-05-20 01:35:19 +02:00
TaskExecutor . Execute ( this . _connectors , task , this . _chapterCollection ) ; //Might crash here, when adding new Task while another Task is running. Check later
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-05-19 20:02:58 +02:00
if ( ! this . _allTasks . Contains ( task ) )
return ;
2023-05-19 19:20:44 +02:00
Task t = new Task ( ( ) = >
{
2023-05-20 01:06:00 +02:00
TaskExecutor . Execute ( this . _connectors , task , this . _chapterCollection ) ;
2023-05-19 19:20:44 +02:00
} ) ;
t . Start ( ) ;
}
2023-05-19 20:03:17 +02:00
/// <summary>
/// Creates and adds a new Task to the task-Collection
/// </summary>
/// <param name="task">TrangaTask.Task to later execute</param>
/// <param name="connectorName">Name of the connector to use</param>
/// <param name="publication">Publication to execute Task on, can be null in case of unrelated Task</param>
/// <param name="reoccurrence">Time-Interval between Executions</param>
/// <param name="language">language, should Task require parameter. Can be empty</param>
/// <exception cref="ArgumentException">Is thrown when connectorName is not a available Connector</exception>
2023-05-20 00:36:52 +02:00
public TrangaTask AddTask ( TrangaTask . Task task , string connectorName , Publication ? publication , TimeSpan reoccurrence ,
2023-05-19 14:15:17 +02:00
string language = "" )
{
2023-05-19 20:22:13 +02:00
//Get appropriate Connector from available Connectors for TrangaTask
2023-05-20 01:06:00 +02:00
Connector ? connector = _connectors . FirstOrDefault ( c = > c . name = = connectorName ) ;
2023-05-19 17:36:03 +02:00
if ( connector is null )
throw new ArgumentException ( $"Connector {connectorName} is not a known connector." ) ;
2023-05-20 00:36:52 +02:00
TrangaTask newTask = new TrangaTask ( connector . name , task , publication , reoccurrence , language ) ;
2023-05-19 20:22:13 +02:00
//Check if same task already exists
2023-05-19 16:35:53 +02:00
if ( ! _allTasks . Any ( trangaTask = > trangaTask . task ! = task & & trangaTask . connectorName ! = connector . name & &
trangaTask . publication ? . downloadUrl ! = publication ? . downloadUrl ) )
{
2023-05-19 18:20:26 +02:00
if ( task ! = TrangaTask . Task . UpdatePublications )
_chapterCollection . Add ( ( Publication ) publication ! , new List < Chapter > ( ) ) ;
2023-05-20 00:36:52 +02:00
_allTasks . Add ( newTask ) ;
2023-05-19 16:35:53 +02:00
ExportTasks ( Directory . GetCurrentDirectory ( ) ) ;
}
2023-05-20 00:36:52 +02:00
return newTask ;
2023-05-19 14:15:17 +02:00
}
2023-05-19 20:03:17 +02:00
/// <summary>
/// Removes Task from task-collection
/// </summary>
/// <param name="task">TrangaTask.Task type</param>
/// <param name="connectorName">Name of Connector that was used</param>
/// <param name="publication">Publication that was used</param>
2023-05-19 16:35:53 +02:00
public void RemoveTask ( TrangaTask . Task task , string connectorName , Publication ? publication )
2023-05-19 14:15:17 +02:00
{
2023-05-19 16:35:53 +02:00
_allTasks . RemoveWhere ( trangaTask = >
trangaTask . task = = task & & trangaTask . connectorName = = connectorName & &
trangaTask . publication ? . downloadUrl = = publication ? . downloadUrl ) ;
ExportTasks ( Directory . GetCurrentDirectory ( ) ) ;
2023-05-19 14:15:17 +02:00
}
2023-05-19 20:03:17 +02:00
/// <summary>
///
/// </summary>
/// <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-19 20:03:17 +02:00
/// <summary>
///
/// </summary>
/// <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-19 17:36:15 +02:00
2023-05-19 20:03:17 +02:00
/// <summary>
///
/// </summary>
/// <returns>All added Publications</returns>
2023-05-19 17:36:15 +02:00
public Publication [ ] GetAllPublications ( )
{
return this . _chapterCollection . Keys . ToArray ( ) ;
}
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
{
_continueRunning = false ;
2023-05-19 14:15:00 +02:00
ExportTasks ( Directory . GetCurrentDirectory ( ) ) ;
2023-05-19 19:21:54 +02:00
if ( force )
Environment . Exit ( _allTasks . Count ( task = > task . isBeingExecuted ) ) ;
//Wait for tasks to finish
while ( _allTasks . Any ( task = > task . isBeingExecuted ) )
Thread . Sleep ( 10 ) ;
2023-05-19 20:22:13 +02:00
Environment . Exit ( 0 ) ;
2023-05-19 13:59:26 +02:00
}
2023-05-19 19:21:15 +02:00
private HashSet < TrangaTask > ImportTasks ( string importFolderPath )
2023-05-19 13:59:26 +02:00
{
2023-05-19 14:15:00 +02:00
string filePath = Path . Join ( importFolderPath , "tasks.json" ) ;
if ( ! File . Exists ( filePath ) )
return new HashSet < TrangaTask > ( ) ;
2023-05-19 16:23:37 +02:00
string toRead = File . ReadAllText ( filePath ) ;
TrangaTask [ ] importTasks = JsonConvert . DeserializeObject < TrangaTask [ ] > ( toRead ) ! ;
foreach ( TrangaTask task in importTasks . Where ( task = > task . publication is not null ) )
this . _chapterCollection . Add ( ( Publication ) task . publication ! , new List < Chapter > ( ) ) ;
2023-05-19 14:15:00 +02:00
return importTasks . ToHashSet ( ) ;
2023-05-19 13:59:26 +02:00
}
2023-05-19 19:21:15 +02:00
private void ExportTasks ( string exportFolderPath )
2023-05-19 13:59:26 +02:00
{
2023-05-19 16:23:37 +02:00
string filePath = Path . Join ( exportFolderPath , "tasks.json" ) ;
string toWrite = JsonConvert . SerializeObject ( _allTasks . ToArray ( ) ) ;
File . WriteAllText ( filePath , toWrite ) ;
2023-05-17 23:23:01 +02:00
}
}