Add enhanced schedule management for background tasks (#267)

This commit is contained in:
Michael Green
2024-01-27 23:30:35 +11:00
committed by GitHub
parent ec115b33de
commit 163aa7a446
20 changed files with 1012 additions and 216 deletions

View File

@@ -73,55 +73,8 @@ When Gaseous-Server is started for the first time, it creates a configuration fi
```
## Docker
### Deploy with the prebuilt Docker image
Dockerfile and docker-compose.yml files have been provided to make deployment of the server as easy as possible.
1. Download the docker-compose-{database}.yml file for the database type you would like to use.
2. Open the docker-compose.yml file and edit the igdbclientid and igdbclientsecret to the values retrieved from your IGDB account
3. Run the command ```docker-compose up -d```
4. Connect to the host on port 5198
### Build and deploy a Docker image from source
Dockerfile and docker-compose-build.yml files have been provided to make deployment of the server as easy as possible.
1. Clone the repo with ```git clone https://github.com/gaseous-project/gaseous-server.git```
2. Change into the gaseous-server directory
3. Open the docker-compose-{database}-build.yml file and edit the igdbclientid and igdbclientsecret to the values retrieved from your IGDB account
4. Run the command ```docker-compose --file docker-compose-{database}-build.yml up -d```
5. Connect to the host on port 5198
## Source
### Build and deploy
1. Install and configure a MariaDB or MySQL instance - this is beyond the scope of this document
2. Install the dotnet 7.0 packages appropriate for your operating system
* See: https://learn.microsoft.com/en-us/dotnet/core/install/linux
3. Create a database user with permission to create a databse. Gaseous will create the new database and apply the database schema on it's first startup.
4. Clone the repo with ```git clone https://github.com/gaseous-project/gaseous-server.git```
5. Change into the gaseous-server directory
6. As the main branch is the development branch, you might want to change to a stable version - these are tagged with a version number. For example to change to the 1.5.0 release, use the command ```git checkout v1.5.0```
* Check the releases page for the version you would like to run: https://github.com/gaseous-project/gaseous-server/releases
7. Download the emulator files from ```https://cdn.emulatorjs.org/releases/4.0.9.zip``` and extract the files to ```gaseous-server/wwwroot/emulators/EmulatorJS```
8. Create a directory in the home directory of the user that will run the server. For example, if running as the user ```gaseous```, create the directory ```/home/gaseous/.gaseous-server```
9. Change into the ```.gaseous-server``` directory created in the previous step
10. Copy the JSON from the config file above into a new file named ```config.json```
11. Update the database section with the database server hostname, username, password, and port
12. Compile the server by changing back to the repo cloned earlier and executing:
* ```dotnet restore "gaseous-server/gaseous-server.csproj"```
* ```dotnet publish "gaseous-server/gaseous-server.csproj" --use-current-runtime --self-contained false -c Release -o <output directory>```
* replace ```<output directory>``` with the directory of your choosing. The compiled application will be copied there. For this example we'll use ```/opt/gaseous-server```
13. The server can then be started by executing ```dotnet /opt/gaseous-server/gaseous-server.dll```
* If you would like the server to run on a different ip address and port (for example 0.0.0.0:8080), add the --urls argument: ```dotnet /opt/gaseous-server/gaseous-server.dll --urls http://0.0.0.0:8080```
**Note**: The above instructions were tested on macOS Ventura, and Ubuntu 22.04.3. There was a report that Debian 11 had an issue with the git submodule commands (see: https://github.com/gaseous-project/gaseous-server/issues/71). This was possibly due to an older git package.
### Updating from source
1. Stop the server
2. Switch to the source directory
3. Update your repo:
* If running from the main branch, run ```git pull``` to update the repo
* If running from another branch or tag, run:
* ```git fetch```
* ```git checkout <branch or tag name>```
4. Run steps 12 and 13 from the above Build guide
# Installation
See https://github.com/gaseous-project/gaseous-server/wiki/Installation for installation instructions.
# Adding Content
While games can be added to the server without them, it is recommended adding some signature DAT files beforehand to allow for better matching of ROMs to games.

View File

@@ -1,5 +1,6 @@
using System.Collections.Concurrent;
using System.ComponentModel;
using System.IO.Compression;
using System.Reflection;
using System.Security.Cryptography;
@@ -120,6 +121,28 @@ namespace gaseous_server.Classes
.Single(x => x.GetValue(null).Equals(value)),
typeof(DescriptionAttribute)))?.Description ?? value.ToString();
}
// compression
public static byte[] Compress(byte[] data)
{
MemoryStream output = new MemoryStream();
using (DeflateStream dstream = new DeflateStream(output, CompressionLevel.Optimal))
{
dstream.Write(data, 0, data.Length);
}
return output.ToArray();
}
public static byte[] Decompress(byte[] data)
{
MemoryStream input = new MemoryStream(data);
MemoryStream output = new MemoryStream();
using (DeflateStream dstream = new DeflateStream(input, CompressionMode.Decompress))
{
dstream.CopyTo(output);
}
return output.ToArray();
}
}
/// <summary>

View File

@@ -3,6 +3,7 @@ using System.Data;
using Newtonsoft.Json;
using IGDB.Models;
using gaseous_server.Classes.Metadata;
using NuGet.Common;
namespace gaseous_server.Classes
{
@@ -161,7 +162,7 @@ namespace gaseous_server.Classes
File.WriteAllText(ConfigurationFilePath, configRaw);
}
private static Dictionary<string, string> AppSettings = new Dictionary<string, string>();
private static Dictionary<string, object> AppSettings = new Dictionary<string, object>();
public static void InitSettings()
{
@@ -172,44 +173,68 @@ namespace gaseous_server.Classes
foreach (DataRow dataRow in dbResponse.Rows)
{
if (AppSettings.ContainsKey((string)dataRow["Setting"]))
{
if ((int)dataRow["ValueType"] == 0)
{
AppSettings[(string)dataRow["Setting"]] = (string)dataRow["Value"];
}
else
{
AppSettings[(string)dataRow["Setting"]] = (DateTime)dataRow["ValueDate"];
}
}
else
{
if ((int)dataRow["ValueType"] == 0)
{
AppSettings.Add((string)dataRow["Setting"], (string)dataRow["Value"]);
}
else
{
AppSettings.Add((string)dataRow["Setting"], (DateTime)dataRow["ValueDate"]);
}
}
}
}
public static string ReadSetting(string SettingName, string DefaultValue)
public static T ReadSetting<T>(string SettingName, T DefaultValue)
{
if (AppSettings.ContainsKey(SettingName))
{
return AppSettings[SettingName];
return (T)AppSettings[SettingName];
}
else
{
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
string sql = "SELECT Value FROM Settings WHERE Setting = @SettingName";
Dictionary<string, object> dbDict = new Dictionary<string, object>();
dbDict.Add("SettingName", SettingName);
dbDict.Add("Value", DefaultValue);
string sql = "SELECT Value, ValueDate FROM Settings WHERE Setting = @SettingName";
Dictionary<string, object> dbDict = new Dictionary<string, object>
{
{ "SettingName", SettingName }
};
try
{
Logging.Log(Logging.LogType.Debug, "Database", "Reading setting '" + SettingName + "'");
DataTable dbResponse = db.ExecuteCMD(sql, dbDict);
Type type = typeof(T);
if (dbResponse.Rows.Count == 0)
{
// no value with that name stored - respond with the default value
SetSetting(SettingName, DefaultValue);
SetSetting<T>(SettingName, DefaultValue);
return DefaultValue;
}
else
{
AppSettings.Add(SettingName, (string)dbResponse.Rows[0][0]);
return (string)dbResponse.Rows[0][0];
if (type.ToString() == "System.DateTime")
{
AppSettings.Add(SettingName, dbResponse.Rows[0]["ValueDate"]);
return (T)dbResponse.Rows[0]["ValueDate"];
}
else
{
AppSettings.Add(SettingName, dbResponse.Rows[0]["Value"]);
return (T)dbResponse.Rows[0]["Value"];
}
}
}
catch (Exception ex)
@@ -220,13 +245,32 @@ namespace gaseous_server.Classes
}
}
public static void SetSetting(string SettingName, string Value)
public static void SetSetting<T>(string SettingName, T Value)
{
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
string sql = "REPLACE INTO Settings (Setting, Value) VALUES (@SettingName, @Value)";
Dictionary<string, object> dbDict = new Dictionary<string, object>();
dbDict.Add("SettingName", SettingName);
dbDict.Add("Value", Value);
string sql = "REPLACE INTO Settings (Setting, ValueType, Value, ValueDate) VALUES (@SettingName, @ValueType, @Value, @ValueDate)";
Dictionary<string, object> dbDict;
Type type = typeof(T);
if (type.ToString() == "System.DateTime")
{
dbDict = new Dictionary<string, object>
{
{ "SettingName", SettingName },
{ "ValueType", 1 },
{ "Value", null },
{ "ValueDate", Value }
};
}
else
{
dbDict = new Dictionary<string, object>
{
{ "SettingName", SettingName },
{ "ValueType", 0 },
{ "Value", Value },
{ "ValueDate", null }
};
}
Logging.Log(Logging.LogType.Debug, "Database", "Storing setting '" + SettingName + "' to value: '" + Value + "'");
try
@@ -341,11 +385,11 @@ namespace gaseous_server.Classes
{
get
{
return ReadSetting("LibraryRootDirectory", Path.Combine(Config.ConfigurationPath, "Data"));
return ReadSetting<string>("LibraryRootDirectory", Path.Combine(Config.ConfigurationPath, "Data"));
}
set
{
SetSetting("LibraryRootDirectory", value);
SetSetting<string>("LibraryRootDirectory", value);
}
}

View File

@@ -452,13 +452,15 @@ namespace gaseous_server.Classes
if (romDT.Rows.Count > 0)
{
foreach (DataRow dr in romDT.Rows)
for (int i = 0; i < romDT.Rows.Count; i++)
{
Logging.Log(Logging.LogType.Information, "Organise Library", "Processing ROM " + dr["name"]);
long RomId = (long)dr["id"];
SetStatus(i, romDT.Rows.Count, "Processing file " + romDT.Rows[i]["name"]);
Logging.Log(Logging.LogType.Information, "Organise Library", "(" + i + "/" + romDT.Rows.Count + ") Processing ROM " + romDT.Rows[i]["name"]);
long RomId = (long)romDT.Rows[i]["id"];
MoveGameFile(RomId);
}
}
ClearStatus();
// clean up empty directories
DeleteOrphanedDirectories(GameLibrary.GetDefaultLibrary.Path);

View File

@@ -9,7 +9,7 @@ namespace gaseous_server.Classes
{
const int MaxFileAge = 30;
public void RunMaintenance()
public void RunDailyMaintenance()
{
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
string sql = "";
@@ -33,8 +33,8 @@ namespace gaseous_server.Classes
}
// delete old logs
sql = "DELETE FROM ServerLogs WHERE EventTime < @EventRententionDate;";
dbDict.Add("EventRententionDate", DateTime.UtcNow.AddDays(Config.LoggingConfiguration.LogRetention * -1));
sql = "DELETE FROM ServerLogs WHERE EventTime < @EventRetentionDate;";
dbDict.Add("EventRetentionDate", DateTime.UtcNow.AddDays(Config.LoggingConfiguration.LogRetention * -1));
db.ExecuteCMD(sql, dbDict);
// delete files and directories older than 7 days in PathsToClean
@@ -69,6 +69,13 @@ namespace gaseous_server.Classes
}
}
}
}
public void RunWeeklyMaintenance()
{
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
string sql = "";
Dictionary<string, object> dbDict = new Dictionary<string, object>();
Logging.Log(Logging.LogType.Information, "Maintenance", "Optimising database tables");
sql = "SHOW FULL TABLES WHERE Table_Type = 'BASE TABLE';";

View File

@@ -12,6 +12,7 @@ using gaseous_server.Classes.Metadata;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Razor.Hosting;
using RestEase;
namespace gaseous_server.Controllers
{
@@ -96,7 +97,7 @@ namespace gaseous_server.Controllers
string ver = "var AppVersion = \"" + Assembly.GetExecutingAssembly().GetName().Version.ToString() + "\";" + Environment.NewLine +
"var DBSchemaVersion = \"" + db.GetDatabaseSchemaVersion() + "\";" + Environment.NewLine +
"var FirstRunStatus = " + Config.ReadSetting("FirstRunStatus", "0") + ";" + Environment.NewLine +
"var FirstRunStatus = " + Config.ReadSetting<string>("FirstRunStatus", "0") + ";" + Environment.NewLine +
"var AgeRatingBoardsStrings = " + JsonSerializer.Serialize(ClassificationBoardsStrings, new JsonSerializerOptions{
WriteIndented = true
}) + ";" + Environment.NewLine +
@@ -113,19 +114,23 @@ namespace gaseous_server.Controllers
[MapToApiVersion("1.0")]
[MapToApiVersion("1.1")]
[HttpGet]
[Route("Settings/BackgroundTasks/Intervals")]
[Route("Settings/BackgroundTasks/Configuration")]
[Authorize(Roles = "Admin")]
[ProducesResponseType(StatusCodes.Status200OK)]
public ActionResult GetBackgroundTasks()
{
Dictionary<string, BackgroundTaskItem> Intervals = new Dictionary<string, BackgroundTaskItem>();
Intervals.Add(ProcessQueue.QueueItemType.SignatureIngestor.ToString(), new BackgroundTaskItem(ProcessQueue.QueueItemType.SignatureIngestor));
Intervals.Add(ProcessQueue.QueueItemType.TitleIngestor.ToString(), new BackgroundTaskItem(ProcessQueue.QueueItemType.TitleIngestor));
Intervals.Add(ProcessQueue.QueueItemType.MetadataRefresh.ToString(), new BackgroundTaskItem(ProcessQueue.QueueItemType.MetadataRefresh));
Intervals.Add(ProcessQueue.QueueItemType.OrganiseLibrary.ToString(), new BackgroundTaskItem(ProcessQueue.QueueItemType.OrganiseLibrary));
Intervals.Add(ProcessQueue.QueueItemType.LibraryScan.ToString(), new BackgroundTaskItem(ProcessQueue.QueueItemType.LibraryScan));
Intervals.Add(ProcessQueue.QueueItemType.Rematcher.ToString(), new BackgroundTaskItem(ProcessQueue.QueueItemType.Rematcher));
Intervals.Add(ProcessQueue.QueueItemType.Maintainer.ToString(), new BackgroundTaskItem(ProcessQueue.QueueItemType.Maintainer));
foreach (ProcessQueue.QueueItemType itemType in Enum.GetValues(typeof(ProcessQueue.QueueItemType)))
{
BackgroundTaskItem taskItem = new BackgroundTaskItem(itemType);
if (taskItem.UserManageable == true)
{
if (!Intervals.ContainsKey(itemType.ToString()))
{
Intervals.Add(itemType.ToString(), taskItem);
}
}
}
return Ok(Intervals);
}
@@ -133,45 +138,102 @@ namespace gaseous_server.Controllers
[MapToApiVersion("1.0")]
[MapToApiVersion("1.1")]
[HttpPost]
[Route("Settings/BackgroundTasks/Intervals")]
[Route("Settings/BackgroundTasks/Configuration")]
[Authorize(Roles = "Admin")]
[ProducesResponseType(StatusCodes.Status200OK)]
public ActionResult SetBackgroundTasks(Dictionary<string, int> Intervals)
public ActionResult SetBackgroundTasks([FromBody] List<BackgroundTaskSettingsItem> model)
{
foreach (KeyValuePair<string, int> Interval in Intervals)
foreach (BackgroundTaskSettingsItem TaskConfiguration in model)
{
if (Enum.IsDefined(typeof(ProcessQueue.QueueItemType), Interval.Key))
if (Enum.IsDefined(typeof(ProcessQueue.QueueItemType), TaskConfiguration.Task))
{
try
{
BackgroundTaskItem taskItem = new BackgroundTaskItem(
(ProcessQueue.QueueItemType)Enum.Parse(typeof(ProcessQueue.QueueItemType), Interval.Key)
(ProcessQueue.QueueItemType)Enum.Parse(typeof(ProcessQueue.QueueItemType), TaskConfiguration.Task)
);
if (Interval.Value >= taskItem.MinimumAllowedValue)
if (taskItem.UserManageable == true)
{
Logging.Log(Logging.LogType.Information, "Update Background Task", "Updating task " + Interval.Key + " with new interval " + Interval.Value);
// update task enabled
Logging.Log(Logging.LogType.Information, "Update Background Task", "Updating task " + TaskConfiguration.Task + " with enabled value " + TaskConfiguration.Enabled.ToString());
Config.SetSetting("Interval_" + Interval.Key, Interval.Value.ToString());
Config.SetSetting<string>("Enabled_" + TaskConfiguration.Task, TaskConfiguration.Enabled.ToString());
// update existing process
foreach (ProcessQueue.QueueItem item in ProcessQueue.QueueItems)
{
if (item.ItemType.ToString().ToLower() == Interval.Key.ToLower())
if (item.ItemType.ToString().ToLower() == TaskConfiguration.Task.ToLower())
{
item.Interval = Interval.Value;
item.Enabled(Boolean.Parse(TaskConfiguration.Enabled.ToString()));
}
}
// update task interval
if (TaskConfiguration.Interval >= taskItem.MinimumAllowedInterval)
{
Logging.Log(Logging.LogType.Information, "Update Background Task", "Updating task " + TaskConfiguration.Task + " with new interval " + TaskConfiguration.Interval);
Config.SetSetting<string>("Interval_" + TaskConfiguration.Task, TaskConfiguration.Interval.ToString());
// update existing process
foreach (ProcessQueue.QueueItem item in ProcessQueue.QueueItems)
{
if (item.ItemType.ToString().ToLower() == TaskConfiguration.Task.ToLower())
{
item.Interval = TaskConfiguration.Interval;
}
}
}
else
{
Logging.Log(Logging.LogType.Warning, "Update Background Task", "Interval " + Interval.Value + " for task " + Interval.Key + " is below the minimum allowed value of " + taskItem.MinimumAllowedValue + ". Skipping.");
Logging.Log(Logging.LogType.Warning, "Update Background Task", "Interval " + TaskConfiguration.Interval.ToString() + " for task " + TaskConfiguration.Task + " is below the minimum allowed value of " + taskItem.MinimumAllowedInterval + ". Skipping.");
}
// update task weekdays
Logging.Log(Logging.LogType.Information, "Update Background Task", "Updating task " + TaskConfiguration.Task + " with new weekdays " + String.Join(", ", TaskConfiguration.AllowedDays));
Config.SetSetting<string>("AllowedDays_" + TaskConfiguration.Task, Newtonsoft.Json.JsonConvert.SerializeObject(TaskConfiguration.AllowedDays));
// update existing process
foreach (ProcessQueue.QueueItem item in ProcessQueue.QueueItems)
{
if (item.ItemType.ToString().ToLower() == TaskConfiguration.Task.ToLower())
{
item.AllowedDays = TaskConfiguration.AllowedDays;
}
}
// update task hours
Logging.Log(Logging.LogType.Information, "Update Background Task", "Updating task " + TaskConfiguration.Task + " with new hours " + TaskConfiguration.AllowedStartHours + ":" + TaskConfiguration.AllowedStartMinutes.ToString("00") + " to " + TaskConfiguration.AllowedEndHours + ":" + TaskConfiguration.AllowedEndMinutes.ToString("00"));
Config.SetSetting<string>("AllowedStartHours_" + TaskConfiguration.Task, TaskConfiguration.AllowedStartHours.ToString());
Config.SetSetting<string>("AllowedStartMinutes_" + TaskConfiguration.Task, TaskConfiguration.AllowedStartMinutes.ToString());
Config.SetSetting<string>("AllowedEndHours_" + TaskConfiguration.Task, TaskConfiguration.AllowedEndHours.ToString());
Config.SetSetting<string>("AllowedEndMinutes_" + TaskConfiguration.Task, TaskConfiguration.AllowedEndMinutes.ToString());
// update existing process
foreach (ProcessQueue.QueueItem item in ProcessQueue.QueueItems)
{
if (item.ItemType.ToString().ToLower() == TaskConfiguration.Task.ToLower())
{
item.AllowedStartHours = TaskConfiguration.AllowedStartHours;
item.AllowedStartMinutes = TaskConfiguration.AllowedStartMinutes;
item.AllowedEndHours = TaskConfiguration.AllowedEndHours;
item.AllowedEndMinutes = TaskConfiguration.AllowedEndMinutes;
}
}
}
else
{
Logging.Log(Logging.LogType.Warning, "Update Background Task", "Unable to update non-user manageable task " + TaskConfiguration.Task + ". Skipping.");
}
}
catch
{
// task name not defined
Logging.Log(Logging.LogType.Warning, "Update Background Task", "Task " + Interval.Key + " is not user definable. Skipping.");
Logging.Log(Logging.LogType.Warning, "Update Background Task", "Task " + TaskConfiguration.Task + " is not user definable. Skipping.");
}
}
}
@@ -256,61 +318,387 @@ namespace gaseous_server.Controllers
public class BackgroundTaskItem
{
public BackgroundTaskItem()
{
}
public BackgroundTaskItem(ProcessQueue.QueueItemType TaskName)
{
this.Task = TaskName.ToString();
this.TaskEnum = TaskName;
switch (TaskName)
{
case ProcessQueue.QueueItemType.SignatureIngestor:
this._UserManageable = true;
this.DefaultInterval = 60;
this.MinimumAllowedValue = 20;
this.MinimumAllowedInterval = 20;
this.DefaultAllowedDays = new List<DayOfWeek>{
DayOfWeek.Sunday,
DayOfWeek.Monday,
DayOfWeek.Tuesday,
DayOfWeek.Wednesday,
DayOfWeek.Thursday,
DayOfWeek.Friday,
DayOfWeek.Saturday
};
this.DefaultAllowedStartHours = 0;
this.DefaultAllowedStartMinutes = 0;
this.DefaultAllowedEndHours = 23;
this.DefaultAllowedEndMinutes = 59;
break;
case ProcessQueue.QueueItemType.TitleIngestor:
this._UserManageable = true;
this.DefaultInterval = 1;
this.MinimumAllowedValue = 1;
this.MinimumAllowedInterval = 1;
this.DefaultAllowedDays = new List<DayOfWeek>{
DayOfWeek.Sunday,
DayOfWeek.Monday,
DayOfWeek.Tuesday,
DayOfWeek.Wednesday,
DayOfWeek.Thursday,
DayOfWeek.Friday,
DayOfWeek.Saturday
};
this.DefaultAllowedStartHours = 0;
this.DefaultAllowedStartMinutes = 0;
this.DefaultAllowedEndHours = 23;
this.DefaultAllowedEndMinutes = 59;
this._Blocks = new List<ProcessQueue.QueueItemType>{
ProcessQueue.QueueItemType.OrganiseLibrary,
ProcessQueue.QueueItemType.LibraryScan,
ProcessQueue.QueueItemType.LibraryScanWorker
};
break;
case ProcessQueue.QueueItemType.MetadataRefresh:
this._UserManageable = true;
this.DefaultInterval = 360;
this.MinimumAllowedValue = 360;
this.MinimumAllowedInterval = 360;
this.DefaultAllowedDays = new List<DayOfWeek>{
DayOfWeek.Sunday,
DayOfWeek.Monday,
DayOfWeek.Tuesday,
DayOfWeek.Wednesday,
DayOfWeek.Thursday,
DayOfWeek.Friday,
DayOfWeek.Saturday
};
this.DefaultAllowedStartHours = 0;
this.DefaultAllowedStartMinutes = 0;
this.DefaultAllowedEndHours = 23;
this.DefaultAllowedEndMinutes = 59;
break;
case ProcessQueue.QueueItemType.OrganiseLibrary:
this._UserManageable = true;
this.DefaultInterval = 1440;
this.MinimumAllowedValue = 120;
this.MinimumAllowedInterval = 120;
this.DefaultAllowedDays = new List<DayOfWeek>{
DayOfWeek.Sunday,
DayOfWeek.Monday,
DayOfWeek.Tuesday,
DayOfWeek.Wednesday,
DayOfWeek.Thursday,
DayOfWeek.Friday,
DayOfWeek.Saturday
};
this.DefaultAllowedStartHours = 0;
this.DefaultAllowedStartMinutes = 0;
this.DefaultAllowedEndHours = 23;
this.DefaultAllowedEndMinutes = 59;
this._Blocks = new List<ProcessQueue.QueueItemType>{
ProcessQueue.QueueItemType.LibraryScan,
ProcessQueue.QueueItemType.LibraryScanWorker,
ProcessQueue.QueueItemType.TitleIngestor,
ProcessQueue.QueueItemType.Rematcher
};
break;
case ProcessQueue.QueueItemType.LibraryScan:
this._UserManageable = true;
this.DefaultInterval = 1440;
this.MinimumAllowedValue = 120;
this.MinimumAllowedInterval = 120;
this.DefaultAllowedDays = new List<DayOfWeek>{
DayOfWeek.Sunday,
DayOfWeek.Monday,
DayOfWeek.Tuesday,
DayOfWeek.Wednesday,
DayOfWeek.Thursday,
DayOfWeek.Friday,
DayOfWeek.Saturday
};
this.DefaultAllowedStartHours = 0;
this.DefaultAllowedStartMinutes = 0;
this.DefaultAllowedEndHours = 23;
this.DefaultAllowedEndMinutes = 59;
this._Blocks = new List<ProcessQueue.QueueItemType>{
ProcessQueue.QueueItemType.OrganiseLibrary,
ProcessQueue.QueueItemType.Rematcher
};
break;
case ProcessQueue.QueueItemType.Rematcher:
this._UserManageable = true;
this.DefaultInterval = 1440;
this.MinimumAllowedValue = 360;
this.MinimumAllowedInterval = 360;
this.DefaultAllowedDays = new List<DayOfWeek>{
DayOfWeek.Sunday,
DayOfWeek.Monday,
DayOfWeek.Tuesday,
DayOfWeek.Wednesday,
DayOfWeek.Thursday,
DayOfWeek.Friday,
DayOfWeek.Saturday
};
this.DefaultAllowedStartHours = 0;
this.DefaultAllowedStartMinutes = 0;
this.DefaultAllowedEndHours = 23;
this.DefaultAllowedEndMinutes = 59;
this._Blocks = new List<ProcessQueue.QueueItemType>{
ProcessQueue.QueueItemType.OrganiseLibrary,
ProcessQueue.QueueItemType.LibraryScan,
ProcessQueue.QueueItemType.LibraryScanWorker
};
break;
case ProcessQueue.QueueItemType.Maintainer:
case ProcessQueue.QueueItemType.DailyMaintainer:
this._UserManageable = true;
this.DefaultInterval = 1440;
this.MinimumAllowedInterval = 1440;
this.DefaultAllowedDays = new List<DayOfWeek>{
DayOfWeek.Sunday,
DayOfWeek.Monday,
DayOfWeek.Tuesday,
DayOfWeek.Wednesday,
DayOfWeek.Thursday,
DayOfWeek.Friday,
DayOfWeek.Saturday
};
this.DefaultAllowedStartHours = 1;
this.DefaultAllowedStartMinutes = 0;
this.DefaultAllowedEndHours = 5;
this.DefaultAllowedEndMinutes = 59;
this._Blocks = new List<ProcessQueue.QueueItemType>{
ProcessQueue.QueueItemType.All
};
break;
case ProcessQueue.QueueItemType.WeeklyMaintainer:
this._UserManageable = true;
this.DefaultInterval = 10080;
this.MinimumAllowedValue = 10080;
this.MinimumAllowedInterval = 10080;
this.DefaultAllowedDays = new List<DayOfWeek>{
DayOfWeek.Monday
};
this.DefaultAllowedStartHours = 1;
this.DefaultAllowedStartMinutes = 0;
this.DefaultAllowedEndHours = 5;
this.DefaultAllowedEndMinutes = 59;
this._Blocks = new List<ProcessQueue.QueueItemType>{
ProcessQueue.QueueItemType.All
};
break;
case ProcessQueue.QueueItemType.BackgroundDatabaseUpgrade:
this._UserManageable = false;
this.DefaultInterval = 1;
this.MinimumAllowedInterval = 1;
this.DefaultAllowedDays = new List<DayOfWeek>{
DayOfWeek.Sunday,
DayOfWeek.Monday,
DayOfWeek.Tuesday,
DayOfWeek.Wednesday,
DayOfWeek.Thursday,
DayOfWeek.Friday,
DayOfWeek.Saturday
};
this.DefaultAllowedStartHours = 0;
this.DefaultAllowedStartMinutes = 0;
this.DefaultAllowedEndHours = 23;
this.DefaultAllowedEndMinutes = 59;
this._Blocks.Add(ProcessQueue.QueueItemType.All);
break;
case ProcessQueue.QueueItemType.TempCleanup:
this._UserManageable = true;
this.DefaultInterval = 1;
this.MinimumAllowedInterval = 1;
this.DefaultAllowedDays = new List<DayOfWeek>{
DayOfWeek.Sunday,
DayOfWeek.Monday,
DayOfWeek.Tuesday,
DayOfWeek.Wednesday,
DayOfWeek.Thursday,
DayOfWeek.Friday,
DayOfWeek.Saturday
};
this.DefaultAllowedStartHours = 0;
this.DefaultAllowedStartMinutes = 0;
this.DefaultAllowedEndHours = 23;
this.DefaultAllowedEndMinutes = 59;
break;
default:
throw new Exception("Invalid task");
this._UserManageable = false;
this.DefaultAllowedDays = new List<DayOfWeek>{
DayOfWeek.Sunday,
DayOfWeek.Monday,
DayOfWeek.Tuesday,
DayOfWeek.Wednesday,
DayOfWeek.Thursday,
DayOfWeek.Friday,
DayOfWeek.Saturday
};
this.DefaultAllowedStartHours = 0;
this.DefaultAllowedStartMinutes = 0;
this.DefaultAllowedEndHours = 23;
this.DefaultAllowedEndMinutes = 59;
break;
}
}
public string Task { get; set; }
public ProcessQueue.QueueItemType TaskEnum { get; set; }
public bool Enabled
{
get
{
if (_UserManageable == true)
{
return bool.Parse(Config.ReadSetting<string>("Enabled_" + Task, true.ToString()));
}
else
{
return true;
}
}
set
{
if (_UserManageable == true)
{
Config.SetSetting<string>("Enabled_" + Task, value.ToString());
}
}
}
private bool _UserManageable;
public bool UserManageable => _UserManageable;
public int Interval {
get
{
return int.Parse(Config.ReadSetting("Interval_" + Task, DefaultInterval.ToString()));
return int.Parse(Config.ReadSetting<string>("Interval_" + Task, DefaultInterval.ToString()));
}
}
public int DefaultInterval { get; set; }
public int MinimumAllowedValue { get; set; }
public int MinimumAllowedInterval { get; set; }
public List<DayOfWeek> AllowedDays
{
get
{
string jsonDefaultAllowedDays = Newtonsoft.Json.JsonConvert.SerializeObject(DefaultAllowedDays);
return Newtonsoft.Json.JsonConvert.DeserializeObject<List<DayOfWeek>>(Config.ReadSetting<string>("AllowedDays_" + Task, jsonDefaultAllowedDays));
}
}
public int AllowedStartHours
{
get
{
return int.Parse(Config.ReadSetting<string>("AllowedStartHours_" + Task, DefaultAllowedStartHours.ToString()));
}
}
public int AllowedStartMinutes
{
get
{
return int.Parse(Config.ReadSetting<string>("AllowedStartMinutes_" + Task, DefaultAllowedStartMinutes.ToString()));
}
}
public int AllowedEndHours
{
get
{
return int.Parse(Config.ReadSetting<string>("AllowedEndHours_" + Task, DefaultAllowedEndHours.ToString()));
}
}
public int AllowedEndMinutes
{
get
{
return int.Parse(Config.ReadSetting<string>("AllowedEndMinutes_" + Task, DefaultAllowedEndMinutes.ToString()));
}
}
public List<DayOfWeek> DefaultAllowedDays { get; set; }
public int DefaultAllowedStartHours { get; set; }
public int DefaultAllowedStartMinutes { get; set; }
public int DefaultAllowedEndHours { get; set; }
public int DefaultAllowedEndMinutes { get; set; }
private List<ProcessQueue.QueueItemType> _Blocks = new List<ProcessQueue.QueueItemType>();
public List<ProcessQueue.QueueItemType> Blocks
{
get
{
if (_Blocks.Contains(ProcessQueue.QueueItemType.All))
{
List<ProcessQueue.QueueItemType> blockList = new List<ProcessQueue.QueueItemType>();
List<ProcessQueue.QueueItemType> skipBlockItems = new List<ProcessQueue.QueueItemType>{
ProcessQueue.QueueItemType.All,
ProcessQueue.QueueItemType.NotConfigured,
this.TaskEnum
};
foreach (ProcessQueue.QueueItemType blockType in Enum.GetValues(typeof(ProcessQueue.QueueItemType)))
{
if (!skipBlockItems.Contains(blockType))
{
blockList.Add(blockType);
}
}
return blockList;
}
else
{
return _Blocks;
}
}
}
public List<ProcessQueue.QueueItemType> BlockedBy
{
get
{
List<ProcessQueue.QueueItemType> blockedBy = new List<ProcessQueue.QueueItemType>();
List<BackgroundTaskItem> backgroundTaskItems = new List<BackgroundTaskItem>();
foreach (ProcessQueue.QueueItemType blockType in Enum.GetValues(typeof(ProcessQueue.QueueItemType)))
{
if (blockType != this.TaskEnum)
{
BackgroundTaskItem taskItem = new BackgroundTaskItem(blockType);
if (taskItem.Blocks.Contains(this.TaskEnum))
{
if (!blockedBy.Contains(blockType))
{
blockedBy.Add(blockType);
}
}
}
}
return blockedBy;
}
}
}
public class BackgroundTaskSettingsItem
{
public string Task { get; set; }
public bool Enabled { get; set; }
public int Interval { get; set; }
public List<DayOfWeek> AllowedDays { get; set; }
public int AllowedStartHours { get; set; }
public int AllowedStartMinutes { get; set; }
public int AllowedEndHours { get; set; }
public int AllowedEndMinutes { get; set; }
}
public class SystemSettingsModel

View File

@@ -40,7 +40,7 @@ namespace gaseous_server.Controllers
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<ActionResult> CreateAdminAccount(Authentication.RegisterViewModel model)
{
if (Config.ReadSetting("FirstRunStatus", "0") == "0")
if (Config.ReadSetting<string>("FirstRunStatus", "0") == "0")
{
if (ModelState.IsValid)
{
@@ -68,7 +68,7 @@ namespace gaseous_server.Controllers
await _signInManager.SignInAsync(user, isPersistent: true);
Logging.Log(Logging.LogType.Information, "First Run", "Setting first run state to 1");
Config.SetSetting("FirstRunStatus", "1");
Config.SetSetting<string>("FirstRunStatus", "1");
return Ok(result);
}

View File

@@ -37,8 +37,10 @@ namespace gaseous_server.Controllers.v1_1
{
var user = await _userManager.GetUserAsync(User);
byte[] CompressedState = Common.Compress(uploadState.StateByteArray);
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
string sql = "INSERT INTO GameState (UserId, RomId, IsMediaGroup, StateDateTime, Name, Screenshot, State) VALUES (@userid, @romid, @ismediagroup, @statedatetime, @name, @screenshot, @state); SELECT LAST_INSERT_ID();";
string sql = "INSERT INTO GameState (UserId, RomId, IsMediaGroup, StateDateTime, Name, Screenshot, State, Zipped) VALUES (@userid, @romid, @ismediagroup, @statedatetime, @name, @screenshot, @state, @zipped); SELECT LAST_INSERT_ID();";
Dictionary<string, object> dbDict = new Dictionary<string, object>
{
{ "userid", user.Id },
@@ -47,10 +49,20 @@ namespace gaseous_server.Controllers.v1_1
{ "statedatetime", DateTime.UtcNow },
{ "name", "" },
{ "screenshot", uploadState.ScreenshotByteArray },
{ "state", uploadState.StateByteArray }
{ "state", CompressedState },
{ "zipped", true }
};
DataTable data = db.ExecuteCMD(sql, dbDict);
if (IsMediaGroup == false)
{
Logging.Log(Logging.LogType.Information, "Save State", "Saved state for rom id " + RomId + ". State size: " + uploadState.StateByteArrayBase64.Length + " Compressed size: " + CompressedState.Length);
}
else
{
Logging.Log(Logging.LogType.Information, "Save State", "Saved state for media group id " + RomId + ". State size: " + uploadState.StateByteArrayBase64.Length + " Compressed size: " + CompressedState.Length);
}
return Ok(await GetStateAsync(RomId, (long)(ulong)data.Rows[0][0], IsMediaGroup));
}
@@ -224,7 +236,7 @@ namespace gaseous_server.Controllers.v1_1
{
var user = await _userManager.GetUserAsync(User);
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
string sql = "SELECT State FROM GameState WHERE Id = @id AND RomId = @romid AND IsMediaGroup = @ismediagroup AND UserId = @userid;";
string sql = "SELECT Zipped, State FROM GameState WHERE Id = @id AND RomId = @romid AND IsMediaGroup = @ismediagroup AND UserId = @userid;";
Dictionary<string, object> dbDict = new Dictionary<string, object>
{
{ "id", StateId },
@@ -242,7 +254,15 @@ namespace gaseous_server.Controllers.v1_1
else
{
string filename = "savestate.state";
byte[] bytes = (byte[])data.Rows[0][0];
byte[] bytes;
if ((bool)data.Rows[0]["Zipped"] == false)
{
bytes = (byte[])data.Rows[0]["State"];
}
else
{
bytes = Common.Decompress((byte[])data.Rows[0]["State"]);
}
string contentType = "application/octet-stream";
var cd = new System.Net.Mime.ContentDisposition

View File

@@ -2,6 +2,8 @@
using System.ComponentModel.Design.Serialization;
using System.Data;
using gaseous_server.Classes;
using gaseous_server.Controllers;
using Microsoft.AspNetCore.Identity.UI.V4.Pages.Account.Manage.Internal;
using NuGet.Common;
using NuGet.Packaging;
@@ -13,25 +15,63 @@ namespace gaseous_server
public class QueueItem
{
public QueueItem(QueueItemType ItemType, bool AllowManualStart = true, bool RemoveWhenStopped = false)
{
_ItemType = ItemType;
_ItemState = QueueItemState.NeverStarted;
_LastRunTime = Config.ReadSetting<DateTime>("LastRun_" + _ItemType.ToString(), DateTime.UtcNow.AddMinutes(-5));
_AllowManualStart = AllowManualStart;
_RemoveWhenStopped = RemoveWhenStopped;
// load queueitem configuration
BackgroundTaskItem defaultItem = new BackgroundTaskItem(ItemType);
Enabled(defaultItem.Enabled);
_Interval = defaultItem.Interval;
_AllowedDays = defaultItem.AllowedDays;
AllowedStartHours = defaultItem.AllowedStartHours;
AllowedStartMinutes = defaultItem.AllowedStartMinutes;
AllowedEndHours = defaultItem.AllowedEndHours;
AllowedEndMinutes = defaultItem.AllowedEndMinutes;
_Blocks = defaultItem.Blocks;
}
public QueueItem(QueueItemType ItemType, int ExecutionInterval, bool AllowManualStart = true, bool RemoveWhenStopped = false)
{
_ItemType = ItemType;
_ItemState = QueueItemState.NeverStarted;
_LastRunTime = DateTime.Parse(Config.ReadSetting("LastRun_" + _ItemType.ToString(), DateTime.UtcNow.ToString("yyyy-MM-ddThh:mm:ssZ"))).AddMinutes(-5);
_LastRunTime = Config.ReadSetting<DateTime>("LastRun_" + _ItemType.ToString(), DateTime.UtcNow.AddMinutes(-5));
_Interval = ExecutionInterval;
_AllowManualStart = AllowManualStart;
_RemoveWhenStopped = RemoveWhenStopped;
// load timing defaults
BackgroundTaskItem defaultItem = new BackgroundTaskItem(ItemType);
Enabled(defaultItem.Enabled);
_AllowedDays = defaultItem.AllowedDays;
AllowedStartHours = defaultItem.AllowedStartHours;
AllowedStartMinutes = defaultItem.AllowedStartMinutes;
AllowedEndHours = defaultItem.AllowedEndHours;
AllowedEndMinutes = defaultItem.AllowedEndMinutes;
}
public QueueItem(QueueItemType ItemType, int ExecutionInterval, List<QueueItemType> Blocks, bool AllowManualStart = true, bool RemoveWhenStopped = false)
{
_ItemType = ItemType;
_ItemState = QueueItemState.NeverStarted;
_LastRunTime = DateTime.Parse(Config.ReadSetting("LastRun_" + _ItemType.ToString(), DateTime.UtcNow.ToString("yyyy-MM-ddThh:mm:ssZ"))).AddMinutes(-5);
_LastRunTime = Config.ReadSetting<DateTime>("LastRun_" + _ItemType.ToString(), DateTime.UtcNow.AddMinutes(-5));
_Interval = ExecutionInterval;
_AllowManualStart = AllowManualStart;
_RemoveWhenStopped = RemoveWhenStopped;
_Blocks = Blocks;
// load timing defaults
BackgroundTaskItem defaultItem = new BackgroundTaskItem(ItemType);
Enabled(defaultItem.Enabled);
_AllowedDays = defaultItem.AllowedDays;
AllowedStartHours = defaultItem.AllowedStartHours;
AllowedStartMinutes = defaultItem.AllowedStartMinutes;
AllowedEndHours = defaultItem.AllowedEndHours;
AllowedEndMinutes = defaultItem.AllowedEndMinutes;
}
private QueueItemType _ItemType = QueueItemType.NotConfigured;
@@ -42,13 +82,15 @@ namespace gaseous_server
{
get
{
return DateTime.Parse(Config.ReadSetting("LastRun_" + _ItemType.ToString(), DateTime.UtcNow.ToString("yyyy-MM-ddThh:mm:ssZ")));
// return DateTime.Parse(Config.ReadSetting("LastRun_" + _ItemType.ToString(), DateTime.UtcNow.ToString("yyyy-MM-ddThh:mm:ssZ")));
return Config.ReadSetting<DateTime>("LastRun_" + _ItemType.ToString(), DateTime.UtcNow);
}
set
{
if (_SaveLastRunTime == true)
{
Config.SetSetting("LastRun_" + _ItemType.ToString(), value.ToString("yyyy-MM-ddThh:mm:ssZ"));
//Config.SetSetting("LastRun_" + _ItemType.ToString(), value.ToString("yyyy-MM-ddThh:mm:ssZ"));
Config.SetSetting<DateTime>("LastRun_" + _ItemType.ToString(), value);
}
}
}
@@ -61,8 +103,33 @@ namespace gaseous_server
private bool _RemoveWhenStopped = false;
private bool _IsBlocked = false;
private string _CorrelationId = "";
private List<DayOfWeek> _AllowedDays = new List<DayOfWeek>
{
DayOfWeek.Sunday,
DayOfWeek.Monday,
DayOfWeek.Tuesday,
DayOfWeek.Wednesday,
DayOfWeek.Thursday,
DayOfWeek.Friday,
DayOfWeek.Saturday
};
private List<QueueItemType> _Blocks = new List<QueueItemType>();
public List<DayOfWeek> AllowedDays
{
get
{
return _AllowedDays;
}
set
{
_AllowedDays = value;
}
}
public int AllowedStartHours { get; set; } = 0;
public int AllowedStartMinutes { get; set; } = 0;
public int AllowedEndHours { get; set; } = 23;
public int AllowedEndMinutes { get; set; } = 59;
public QueueItemType ItemType => _ItemType;
public QueueItemState ItemState => _ItemState;
public DateTime LastRunTime => _LastRunTime;
@@ -72,9 +139,56 @@ namespace gaseous_server
{
get
{
return LastRunTime.AddMinutes(Interval);
// next run time
DateTime tempNextRun = LastRunTime.ToLocalTime().AddMinutes(Interval);
// if (tempNextRun < DateTime.Now)
// {
// tempNextRun = DateTime.Now;
// }
DayOfWeek nextWeekDay = tempNextRun.DayOfWeek;
// create local start and end times
DateTime tempStartTime = new DateTime(tempNextRun.Year, tempNextRun.Month, tempNextRun.Day, AllowedStartHours, AllowedStartMinutes, 0, DateTimeKind.Local);
DateTime tempEndTime = new DateTime(tempNextRun.Year, tempNextRun.Month, tempNextRun.Day, AllowedEndHours, AllowedEndMinutes, 0, DateTimeKind.Local);
// bump the next run time to the next allowed day and hour range
if (AllowedDays.Contains(nextWeekDay))
{
// next run day is allowed, nothing to do
}
else
{
// keep bumping the day forward until the a weekday is found
do
{
tempNextRun = tempNextRun.AddDays(1);
nextWeekDay = tempNextRun.DayOfWeek;
}
while (!AllowedDays.Contains(nextWeekDay));
// update windows
tempStartTime = new DateTime(tempNextRun.Year, tempNextRun.Month, tempNextRun.Day, AllowedStartHours, AllowedStartMinutes, 0, DateTimeKind.Local);
tempEndTime = new DateTime(tempNextRun.Year, tempNextRun.Month, tempNextRun.Day, AllowedEndHours, AllowedEndMinutes, 0, DateTimeKind.Local);
}
// are the hours in the right range
TimeSpan spanNextRun = tempNextRun.TimeOfDay;
if (LastRunTime.ToLocalTime().AddMinutes(Interval) < tempStartTime)
{
return tempStartTime.ToUniversalTime();
}
else if (spanNextRun >= tempStartTime.TimeOfDay && spanNextRun <= tempEndTime.TimeOfDay)
{
// all good - return nextRun
return tempNextRun.ToUniversalTime();
}
else
{
return tempStartTime.ToUniversalTime();
}
}
}
public int Interval
{
get
@@ -233,12 +347,25 @@ namespace gaseous_server
DatabaseMigration.UpgradeScriptBackgroundTasks();
break;
case QueueItemType.Maintainer:
Logging.Log(Logging.LogType.Debug, "Timered Event", "Starting Maintenance");
case QueueItemType.DailyMaintainer:
Logging.Log(Logging.LogType.Debug, "Timered Event", "Starting Daily Maintenance");
Classes.Maintenance maintenance = new Maintenance{
CallingQueueItem = this
};
maintenance.RunMaintenance();
maintenance.RunDailyMaintenance();
_SaveLastRunTime = true;
break;
case QueueItemType.WeeklyMaintainer:
Logging.Log(Logging.LogType.Debug, "Timered Event", "Starting Weekly Maintenance");
Classes.Maintenance weeklyMaintenance = new Maintenance{
CallingQueueItem = this
};
weeklyMaintenance.RunWeeklyMaintenance();
_SaveLastRunTime = true;
break;
case QueueItemType.TempCleanup:
@@ -277,7 +404,14 @@ namespace gaseous_server
}
_ForceExecute = false;
if (_DisableWhenComplete == false)
{
_ItemState = QueueItemState.Stopped;
}
else
{
_ItemState = QueueItemState.Disabled;
}
_LastFinishTime = DateTime.UtcNow;
_LastRunDuration = Math.Round((DateTime.UtcNow - _LastRunTime).TotalSeconds, 2);
@@ -296,6 +430,26 @@ namespace gaseous_server
_IsBlocked = BlockState;
}
private bool _DisableWhenComplete = false;
public void Enabled(bool Enabled)
{
_DisableWhenComplete = !Enabled;
if (Enabled == true)
{
if (_ItemState == QueueItemState.Disabled)
{
_ItemState = QueueItemState.Stopped;
}
}
else
{
if (_ItemState == QueueItemState.Stopped || _ItemState == QueueItemState.NeverStarted)
{
_ItemState = QueueItemState.Disabled;
}
}
}
public HasErrorsItem HasErrors
{
get
@@ -420,9 +574,14 @@ namespace gaseous_server
BackgroundDatabaseUpgrade,
/// <summary>
/// Performs a clean up of old files, and optimises the database
/// Performs a clean up of old files, and purge old logs
/// </summary>
Maintainer,
DailyMaintainer,
/// <summary>
/// Performs more intensive cleanups and optimises the database
/// </summary>
WeeklyMaintainer,
/// <summary>
/// Cleans up marked paths in the temporary directory

View File

@@ -55,15 +55,6 @@ Communications.MetadataSource = Config.MetadataConfiguration.MetadataSource;
// set up hasheous client
HasheousClient.WebApp.HttpHelper.BaseUri = Config.MetadataConfiguration.HasheousHost;
// set initial values
Guid APIKey = Guid.NewGuid();
if (Config.ReadSetting("API Key", "Test API Key") == "Test API Key")
{
// it's a new api key save it
Logging.Log(Logging.LogType.Information, "Startup", "Setting initial API key");
Config.SetSetting("API Key", APIKey.ToString());
}
// clean up storage
if (Directory.Exists(Config.LibraryConfiguration.LibraryTempDirectory))
{
@@ -421,69 +412,38 @@ var platformMap = PlatformMapping.PlatformMap;
// add background tasks
ProcessQueue.QueueItems.Add(new ProcessQueue.QueueItem(
ProcessQueue.QueueItemType.SignatureIngestor,
int.Parse(Config.ReadSetting("Interval_SignatureIngestor", "60"))
)
ProcessQueue.QueueItemType.SignatureIngestor)
);
ProcessQueue.QueueItems.Add(new ProcessQueue.QueueItem(
ProcessQueue.QueueItemType.TitleIngestor,
int.Parse(Config.ReadSetting("Interval_TitleIngestor", "1")),
new List<ProcessQueue.QueueItemType>
{
ProcessQueue.QueueItemType.OrganiseLibrary,
ProcessQueue.QueueItemType.LibraryScan
})
ProcessQueue.QueueItemType.TitleIngestor)
);
ProcessQueue.QueueItems.Add(new ProcessQueue.QueueItem(
ProcessQueue.QueueItemType.MetadataRefresh,
int.Parse(Config.ReadSetting("Interval_MetadataRefresh", "360"))
)
ProcessQueue.QueueItemType.MetadataRefresh)
);
ProcessQueue.QueueItems.Add(new ProcessQueue.QueueItem(
ProcessQueue.QueueItemType.OrganiseLibrary,
int.Parse(Config.ReadSetting("Interval_OrganiseLibrary", "1440")),
new List<ProcessQueue.QueueItemType>
{
ProcessQueue.QueueItemType.LibraryScan,
ProcessQueue.QueueItemType.TitleIngestor,
ProcessQueue.QueueItemType.Rematcher
})
ProcessQueue.QueueItemType.OrganiseLibrary)
);
ProcessQueue.QueueItems.Add(new ProcessQueue.QueueItem(
ProcessQueue.QueueItemType.LibraryScan,
int.Parse(Config.ReadSetting("Interval_LibraryScan", "1440")),
new List<ProcessQueue.QueueItemType>
{
ProcessQueue.QueueItemType.OrganiseLibrary,
ProcessQueue.QueueItemType.Rematcher
})
ProcessQueue.QueueItemType.LibraryScan)
);
ProcessQueue.QueueItems.Add(new ProcessQueue.QueueItem(
ProcessQueue.QueueItemType.Rematcher,
int.Parse(Config.ReadSetting("Interval_Rematcher", "1440")),
new List<ProcessQueue.QueueItemType>
{
ProcessQueue.QueueItemType.OrganiseLibrary,
ProcessQueue.QueueItemType.LibraryScan
})
);
ProcessQueue.QueueItems.Add(new ProcessQueue.QueueItem(
ProcessQueue.QueueItemType.Maintainer,
int.Parse(Config.ReadSetting("Interval_Maintainer", "10080")),
new List<ProcessQueue.QueueItemType>
{
ProcessQueue.QueueItemType.All
})
ProcessQueue.QueueItemType.Rematcher)
);
ProcessQueue.QueueItem tempCleanup = new ProcessQueue.QueueItem(
ProcessQueue.QueueItemType.TempCleanup,
1,
new List<ProcessQueue.QueueItemType>(),
false,
false
// maintenance tasks
ProcessQueue.QueueItem dailyMaintenance = new ProcessQueue.QueueItem(
ProcessQueue.QueueItemType.DailyMaintainer
);
ProcessQueue.QueueItems.Add(dailyMaintenance);
ProcessQueue.QueueItem weeklyMaintenance = new ProcessQueue.QueueItem(
ProcessQueue.QueueItemType.WeeklyMaintainer
);
ProcessQueue.QueueItems.Add(weeklyMaintenance);
ProcessQueue.QueueItem tempCleanup = new ProcessQueue.QueueItem(
ProcessQueue.QueueItemType.TempCleanup
);
tempCleanup.ForceExecute();
ProcessQueue.QueueItems.Add(tempCleanup);
Logging.WriteToDiskOnly = false;

View File

@@ -0,0 +1,6 @@
ALTER TABLE `Settings`
ADD COLUMN `ValueType` INT NULL DEFAULT 0 AFTER `Setting`,
ADD COLUMN `ValueDate` DATETIME NULL DEFAULT NULL AFTER `Value`;
ALTER TABLE `GameState`
ADD COLUMN `Zipped` BOOLEAN NOT NULL DEFAULT 0;

View File

@@ -20,8 +20,8 @@ namespace gaseous_server
//_logger.LogInformation("Timed Hosted Service running.");
Logging.Log(Logging.LogType.Debug, "Background", "Starting background task monitor");
_timer = new Timer(DoWork, null, TimeSpan.Zero,
TimeSpan.FromSeconds(5));
_timer = new Timer(DoWork, null, TimeSpan.FromSeconds(30),
TimeSpan.FromSeconds(30));
return Task.CompletedTask;
}
@@ -36,6 +36,8 @@ namespace gaseous_server
List<ProcessQueue.QueueItem> ActiveList = new List<ProcessQueue.QueueItem>();
ActiveList.AddRange(ProcessQueue.QueueItems);
foreach (ProcessQueue.QueueItem qi in ActiveList) {
if (qi.ItemState != ProcessQueue.QueueItemState.Disabled)
{
if (CheckIfProcessIsBlockedByOthers(qi) == false) {
qi.BlockedState(false);
if (DateTime.UtcNow > qi.NextRunTime || qi.Force == true)
@@ -53,6 +55,7 @@ namespace gaseous_server
}
}
}
}
public Task StopAsync(CancellationToken stoppingToken)
{

View File

@@ -60,6 +60,7 @@
<None Remove="Support\Database\MySQL\gaseous-1013.sql" />
<None Remove="Support\Database\MySQL\gaseous-1014.sql" />
<None Remove="Support\Database\MySQL\gaseous-1015.sql" />
<None Remove="Support\Database\MySQL\gaseous-1016.sql" />
<None Remove="Classes\Metadata\" />
</ItemGroup>
<ItemGroup>
@@ -97,5 +98,6 @@
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1013.sql" />
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1014.sql" />
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1015.sql" />
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1016.sql" />
</ItemGroup>
</Project>

View File

@@ -29,6 +29,7 @@
EJS_pathtodata = '/emulators/EmulatorJS/data/';
EJS_DEBUG_XX = false;
console.log("Debug enabled: " + EJS_DEBUG_XX);
EJS_backgroundImage = emuBackground;
EJS_backgroundBlur = true;

View File

@@ -268,7 +268,7 @@
if (newPassword.length > 0) {
if (newPassword == conPassword) {
// check if password meets requirements
if (newPassword.length > 10) {
if (newPassword.length >= 10) {
errorLabel.innerHTML = "";
submitButton.removeAttribute('disabled');
return true;

View File

@@ -49,7 +49,7 @@
if (userNameVal.includes("@")) {
if (newPassword == conPassword) {
// check if password meets requirements
if (newPassword.length > 10) {
if (newPassword.length >= 10) {
errorLabel.innerHTML = "";
submitButton.removeAttribute('disabled');
} else {

View File

@@ -285,7 +285,7 @@
} else {
if (newPassword == conPassword) {
// check if password meets requirements
if (newPassword.length > 10) {
if (newPassword.length >= 10) {
errorLabel.innerHTML = "";
submitButton.removeAttribute('disabled');
} else {

View File

@@ -117,7 +117,7 @@
} else {
if (newPassword == conPassword) {
// check if password meets requirements
if (newPassword.length > 10) {
if (newPassword.length >= 10) {
errorLabel.innerHTML = "&nbsp;";
submitButton.removeAttribute('disabled');
} else {

View File

@@ -11,7 +11,6 @@
<h2>Advanced Settings</h2>
<p><strong>Warning</strong> Do not modify the below settings unless you know what you're doing.</p>
<h3>Background Task Timers</h3>
<p>All intervals are in minutes.</p>
<table id="settings_tasktimers" class="romtable" style="width: 100%;" cellspacing="0">
</table>
@@ -104,44 +103,241 @@
function getBackgroundTaskTimers() {
ajaxCall(
'/api/v1/System/Settings/BackgroundTasks/Intervals',
'/api/v1/System/Settings/BackgroundTasks/Configuration',
'GET',
function(result) {
var targetTable = document.getElementById('settings_tasktimers');
targetTable.innerHTML = '';
targetTable.appendChild(
createTableRow(true, ['Background Task', 'Timer Interval', 'Default Interval', 'Minimum Allowed Interval'])
);
for (const [key, value] of Object.entries(result)) {
var newTableRow = createTableRow(
var newTableRowBody = document.createElement('tbody');
newTableRowBody.className = 'romrow';
var enabledString = "";
if (value.enabled == true) {
enabledString = 'checked="checked"';
}
var newTableIntervalRow = createTableRow(
false,
[
GetTaskFriendlyName(value.task),
'<input id="settings_tasktimers_' + value.task + '" name="settings_tasktimers_values" data-name="' + value.task + '" data-default="' + value.defaultInterval + '" type="number" placeholder="0" min="' + value.minimumAllowedValue + '" value="' + value.interval + '" />',
value.defaultInterval,
value.minimumAllowedValue
'Enabled',
'<input id="settings_enabled_' + value.task + '" name="settings_tasktimers_enabled" type="checkbox" ' + enabledString + '/>',
],
'romrow',
'',
'romcell'
);
targetTable.appendChild(newTableRow);
newTableRowBody.appendChild(newTableIntervalRow);
var newTableRow = createTableRow(
false,
[
'',
'Minimum Interval (Minutes):',
'<input id="settings_tasktimers_' + value.task + '" name="settings_tasktimers_values" data-name="' + value.task + '" data-default="' + value.defaultInterval + '" type="number" placeholder="' + value.defaultInterval + '" min="' + value.minimumAllowedInterval + '" value="' + value.interval + '" />'
],
'',
'romcell'
);
newTableRowBody.appendChild(newTableRow);
// allowed time periods row
var newTableRowTime = document.createElement('tr');
var rowTimeSpace = document.createElement('td');
newTableRowTime.appendChild(rowTimeSpace);
var rowTimeContentTitle = document.createElement('td');
rowTimeContentTitle.className = 'romcell';
rowTimeContentTitle.innerHTML = "Allowed Days:";
newTableRowTime.appendChild(rowTimeContentTitle);
var rowTimeContent = document.createElement('td');
// rowTimeContent.setAttribute('colspan', 2);
rowTimeContent.className = 'romcell';
var daySelector = document.createElement('select');
daySelector.id = 'settings_alloweddays_' + value.task;
daySelector.name = 'settings_alloweddays';
daySelector.multiple = 'multiple';
daySelector.setAttribute('data-default', value.defaultAllowedDays.join(","));
daySelector.style.width = '95%';
var days = [ "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" ];
for (var d = 0; d < days.length; d++) {
var dayOpt = document.createElement('option');
dayOpt.value = days[d];
dayOpt.innerHTML = days[d];
if (value.allowedDays.includes(days[d])) {
dayOpt.selected = 'selected';
}
daySelector.appendChild(dayOpt);
}
rowTimeContent.appendChild(daySelector);
$(daySelector).select2({
tags: false
});
newTableRowTime.appendChild(rowTimeContent);
newTableRowBody.appendChild(newTableRowTime);
// add start and end times
var newTableRowClock = document.createElement('tr');
var rowClockSpace = document.createElement('td');
newTableRowClock.appendChild(rowClockSpace);
var rowClockContentTitle = document.createElement('td');
rowClockContentTitle.className = 'romcell';
rowClockContentTitle.innerHTML = "Time Range:";
newTableRowClock.appendChild(rowClockContentTitle);
var rowClockContent = document.createElement('td');
rowClockContent.className = 'romcell';
// rowClockContent.setAttribute('colspan', 2);
rowClockContent.appendChild(generateTimeDropDowns(value.task, 'Start', value.defaultAllowedStartHours, value.defaultAllowedStartMinutes, value.allowedStartHours, value.allowedStartMinutes));
rowClockContentSeparator = document.createElement('span');
rowClockContentSeparator.innerHTML = '&nbsp;-&nbsp;';
rowClockContent.appendChild(rowClockContentSeparator);
rowClockContent.appendChild(generateTimeDropDowns(value.task, 'End', value.defaultAllowedEndHours, value.defaultAllowedEndMinutes, value.allowedEndHours, value.allowedEndMinutes));
newTableRowClock.appendChild(rowClockContent);
newTableRowBody.appendChild(newTableRowClock);
// blocks tasks
var newTableRowBlocks = document.createElement('tr');
var rowBlocksSpace = document.createElement('td');
newTableRowBlocks.appendChild(rowBlocksSpace);
var rowBlocksContentTitle = document.createElement('td');
rowBlocksContentTitle.className = 'romcell';
rowBlocksContentTitle.innerHTML = "Blocks:";
newTableRowBlocks.appendChild(rowBlocksContentTitle);
var rowBlocksContent = document.createElement('td');
rowBlocksContent.className = 'romcell';
// rowBlocksContent.setAttribute('colspan', 2);
var blocksString = "";
for (var i = 0; i < value.blocks.length; i++) {
if (blocksString.length > 0) { blocksString += ", "; }
blocksString += GetTaskFriendlyName(value.blocks[i]);
}
if (blocksString.length == 0) { blocksString = 'None'; }
rowBlocksContent.innerHTML = blocksString;
newTableRowBlocks.appendChild(rowBlocksContent);
newTableRowBody.appendChild(newTableRowBlocks);
// blocked by tasks
var newTableRowBlockedBy = document.createElement('tr');
var rowBlockedBySpace = document.createElement('td');
newTableRowBlockedBy.appendChild(rowBlockedBySpace);
var rowBlockedByContentTitle = document.createElement('td');
rowBlockedByContentTitle.className = 'romcell';
rowBlockedByContentTitle.innerHTML = "Blocked By:";
newTableRowBlockedBy.appendChild(rowBlockedByContentTitle);
var rowBlockedByContent = document.createElement('td');
rowBlockedByContent.className = 'romcell';
// rowBlockedByContent.setAttribute('colspan', 2);
var BlockedByString = "";
for (var i = 0; i < value.blockedBy.length; i++) {
if (BlockedByString.length > 0) { BlockedByString += ", "; }
BlockedByString += GetTaskFriendlyName(value.blockedBy[i]);
}
if (BlockedByString.length == 0) { BlockedByString = 'None'; }
rowBlockedByContent.innerHTML = BlockedByString;
newTableRowBlockedBy.appendChild(rowBlockedByContent);
newTableRowBody.appendChild(newTableRowBlockedBy);
// complete row
targetTable.appendChild(newTableRowBody);
}
}
);
}
function generateTimeDropDowns(taskName, rangeName, defaultHour, defaultMinute, valueHour, valueMinute) {
var container = document.createElement('div');
container.style.display = 'inline';
var elementName = 'settings_tasktimers_time';
var hourSelector = document.createElement('input');
hourSelector.id = 'settings_tasktimers_' + taskName + '_' + rangeName + '_Hour';
hourSelector.name = elementName;
hourSelector.setAttribute('data-name', taskName);
hourSelector.setAttribute('type', 'number');
hourSelector.setAttribute('min', '0');
hourSelector.setAttribute('max', '23');
hourSelector.setAttribute('placeholder', defaultHour);
hourSelector.value = valueHour;
container.appendChild(hourSelector);
var separator = document.createElement('span');
separator.innerHTML = " : ";
container.appendChild(separator);
var minSelector = document.createElement('input');
minSelector.id = 'settings_tasktimers_' + taskName + '_' + rangeName + '_Minute';
minSelector.name = elementName;
minSelector.setAttribute('type', 'number');
minSelector.setAttribute('min', '0');
minSelector.setAttribute('max', '59');
minSelector.setAttribute('placeholder', defaultMinute);
minSelector.value = valueMinute;
container.appendChild(minSelector);
return container;
}
function saveTaskTimers() {
var timerValues = document.getElementsByName('settings_tasktimers_values');
var model = {};
var model = [];
for (var i = 0; i < timerValues.length; i++) {
model[timerValues[i].getAttribute('data-name')] = timerValues[i].value;
var taskName = timerValues[i].getAttribute('data-name');
var taskEnabled = document.getElementById('settings_enabled_' + taskName).checked;
var taskIntervalObj = document.getElementById('settings_tasktimers_' + taskName);
var taskInterval = function() { if (taskIntervalObj.value) { return taskIntervalObj.value; } else { return taskIntervalObj.getAttribute('placeholder'); } };
var taskDaysRaw = $('#settings_alloweddays_' + taskName).select2('data');
var taskDays = [];
if (taskDaysRaw.length > 0) {
for (var d = 0; d < taskDaysRaw.length; d++) {
taskDays.push(taskDaysRaw[d].id);
}
} else {
taskDays.push("Monday");
}
var taskStartHourObj = document.getElementById('settings_tasktimers_' + taskName + '_Start_Hour');
var taskStartMinuteObj = document.getElementById('settings_tasktimers_' + taskName + '_Start_Minute');
var taskEndHourObj = document.getElementById('settings_tasktimers_' + taskName + '_End_Hour');
var taskEndMinuteObj = document.getElementById('settings_tasktimers_' + taskName + '_End_Minute');
var taskStartHour = function() { if (taskStartHourObj.value) { return taskStartHourObj.value; } else { return taskStartHourObj.getAttribute('placeholder'); } };
var taskStartMinute = function() { if (taskStartMinuteObj.value) { return taskStartMinuteObj.value; } else { return taskStartMinuteObj.getAttribute('placeholder'); } };
var taskEndHour = function() { if (taskEndHourObj.value) { return taskEndHourObj.value; } else { return taskEndHourObj.getAttribute('placeholder'); } };
var taskEndMinute = function() { if (taskEndMinuteObj.value) { return taskEndMinuteObj.value; } else { return taskEndMinuteObj.getAttribute('placeholder'); } };
model.push(
{
"task": taskName,
"enabled": taskEnabled,
"interval": taskInterval(),
"allowedDays": taskDays,
"allowedStartHours": taskStartHour(),
"allowedStartMinutes": taskStartMinute(),
"allowedEndHours": taskEndHour(),
"allowedEndMinutes": taskEndMinute()
}
);
}
ajaxCall(
'/api/v1/System/Settings/BackgroundTasks/Intervals',
'/api/v1/System/Settings/BackgroundTasks/Configuration',
'POST',
function(result) {
getBackgroundTaskTimers();
@@ -154,12 +350,32 @@
}
function defaultTaskTimers() {
var timerValues = document.getElementsByName('settings_tasktimers_enabled');
for (var i = 0; i < timerValues.length; i++) {
timerValues[i].checked = true;
}
var timerValues = document.getElementsByName('settings_tasktimers_values');
for (var i = 0; i < timerValues.length; i++) {
timerValues[i].value = timerValues[i].getAttribute('data-default');
}
var timerValues = document.getElementsByName('settings_alloweddays');
for (var i = 0; i < timerValues.length; i++) {
var defaultSelections = timerValues[i].getAttribute('data-default').split(',');
$(timerValues[i]).val(defaultSelections);
$(timerValues[i]).trigger('change');
}
var timerValues = document.getElementsByName('settings_tasktimers_time');
for (var i = 0; i < timerValues.length; i++) {
timerValues[i].value = timerValues[i].getAttribute('placeholder');
}
saveTaskTimers();
}

View File

@@ -410,13 +410,25 @@ function GetTaskFriendlyName(TaskName, options) {
case 'LibraryScan':
return "Library scan";
case 'LibraryScanWorker':
if (options) {
return "Library scan worker: " + options.name;
} else {
return "Library scan worker";
}
case 'CollectionCompiler':
if (options) {
return "Compress collection id: " + options;
} else {
return "Compress collection";
}
case 'BackgroundDatabaseUpgrade':
return "Background database upgrade";
case 'TempCleanup':
return "Temporary directory cleanup";
case 'DailyMaintainer':
return "Daily maintenance";
case 'WeeklyMaintainer':
return "Weekly maintenance";
default:
return TaskName;
}