Weighted Shortest Job First Hub
This commit is contained in:
parent
ca4ebff54c
commit
08a23114c9
@ -224,7 +224,7 @@ public class FileRead : Shared.FileRead, IFileRead
|
||||
string body = string.Concat(exception.Message, Environment.NewLine, Environment.NewLine, exception.StackTrace);
|
||||
try
|
||||
{
|
||||
_SMTP.SendHighPriorityEmailMessage(subject, body);
|
||||
_SMTP.SendHighPriorityEmailMessage(subject, body);
|
||||
File.WriteAllText(".email", body);
|
||||
}
|
||||
catch (Exception) { }
|
||||
@ -242,7 +242,7 @@ public class FileRead : Shared.FileRead, IFileRead
|
||||
string body = string.Concat(exception.Message, Environment.NewLine, Environment.NewLine, exception.StackTrace);
|
||||
try
|
||||
{
|
||||
_SMTP.SendHighPriorityEmailMessage(subject, body);
|
||||
_SMTP.SendHighPriorityEmailMessage(subject, body);
|
||||
File.WriteAllText(".email", body);
|
||||
}
|
||||
catch (Exception) { }
|
||||
|
@ -138,7 +138,7 @@ public class FileRead : Shared.FileRead, IFileRead
|
||||
string body = string.Concat(exception.Message, Environment.NewLine, Environment.NewLine, exception.StackTrace);
|
||||
try
|
||||
{
|
||||
_SMTP.SendHighPriorityEmailMessage(subject, body);
|
||||
_SMTP.SendHighPriorityEmailMessage(subject, body);
|
||||
File.WriteAllText(".email", body);
|
||||
}
|
||||
catch (Exception) { }
|
||||
@ -269,7 +269,7 @@ public class FileRead : Shared.FileRead, IFileRead
|
||||
string body = string.Concat(exception.Message, Environment.NewLine, Environment.NewLine, exception.StackTrace);
|
||||
try
|
||||
{
|
||||
_SMTP.SendHighPriorityEmailMessage(subject, body);
|
||||
_SMTP.SendHighPriorityEmailMessage(subject, body);
|
||||
File.WriteAllText(".email", body);
|
||||
}
|
||||
catch (Exception) { }
|
||||
@ -285,7 +285,7 @@ public class FileRead : Shared.FileRead, IFileRead
|
||||
string body = string.Concat(exception.Message, Environment.NewLine, Environment.NewLine, exception.StackTrace);
|
||||
try
|
||||
{
|
||||
_SMTP.SendHighPriorityEmailMessage(subject, body);
|
||||
_SMTP.SendHighPriorityEmailMessage(subject, body);
|
||||
File.WriteAllText(".email", body);
|
||||
}
|
||||
catch (Exception) { }
|
||||
|
@ -110,6 +110,8 @@ public class ProcessData : IProcessData
|
||||
private static FileInfo GetFileInfoAndMaybeWriteFile(string directory, WorkItem workItem)
|
||||
{
|
||||
FileInfo result;
|
||||
if (!Directory.Exists(directory))
|
||||
_ = Directory.CreateDirectory(directory);
|
||||
string json = JsonSerializer.Serialize(workItem, WorkItemSourceGenerationContext.Default.WorkItem);
|
||||
string singletonDirectory = Path.Combine(directory, $"{workItem.Id}");
|
||||
if (Directory.Exists(singletonDirectory))
|
||||
@ -213,9 +215,13 @@ public class ProcessData : IProcessData
|
||||
{
|
||||
string old;
|
||||
string checkFile;
|
||||
string checkDirectory;
|
||||
foreach (string iterationPath in distinct)
|
||||
{
|
||||
checkFile = Path.Combine(destinationDirectory, iterationPath, "[].json");
|
||||
checkDirectory = Path.Combine(destinationDirectory, iterationPath);
|
||||
if (!Directory.Exists(checkDirectory))
|
||||
_ = Directory.CreateDirectory(checkDirectory);
|
||||
checkFile = Path.Combine(checkDirectory, "[].json");
|
||||
old = File.Exists(checkFile) ? File.ReadAllText(checkFile) : string.Empty;
|
||||
if (old != json)
|
||||
File.WriteAllText(checkFile, json);
|
||||
|
@ -1,38 +1,192 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Adaptation.FileHandlers.Priority;
|
||||
|
||||
#nullable enable
|
||||
|
||||
public class Aggregation
|
||||
{
|
||||
|
||||
[JsonConstructor]
|
||||
public Aggregation(
|
||||
string average,
|
||||
int count,
|
||||
int? inverse,
|
||||
int maximum,
|
||||
int minimum,
|
||||
ReadOnlyCollection<Record> records,
|
||||
int sum
|
||||
)
|
||||
public Aggregation(double inverseAverage,
|
||||
int valueCount,
|
||||
double fibonacciAverage,
|
||||
int? inverseValue,
|
||||
int valueMaximum,
|
||||
int valueMinimum,
|
||||
Notification[] notifications,
|
||||
int valueSum)
|
||||
{
|
||||
Average = average;
|
||||
Count = count;
|
||||
Inverse = inverse;
|
||||
Maximum = maximum;
|
||||
Minimum = minimum;
|
||||
Records = records;
|
||||
Sum = sum;
|
||||
InverseAverage = inverseAverage;
|
||||
ValueCount = valueCount;
|
||||
FibonacciAverage = fibonacciAverage;
|
||||
InverseValue = inverseValue;
|
||||
ValueMaximum = valueMaximum;
|
||||
ValueMinimum = valueMinimum;
|
||||
Notifications = notifications;
|
||||
ValueSum = valueSum;
|
||||
}
|
||||
|
||||
[JsonPropertyName("Average")] public string Average { get; }
|
||||
[JsonPropertyName("Count")] public int Count { get; }
|
||||
[JsonPropertyName("Inverse")] public int? Inverse { get; }
|
||||
[JsonPropertyName("Maximum")] public int Maximum { get; }
|
||||
[JsonPropertyName("Minimum")] public int Minimum { get; }
|
||||
[JsonPropertyName("Records")] public ReadOnlyCollection<Record> Records { get; }
|
||||
[JsonPropertyName("Sum")] public int Sum { get; }
|
||||
public double InverseAverage { get; } // [JsonPropertyName("InverseAverage")]
|
||||
public int ValueCount { get; } // [JsonPropertyName("ValueCount")]
|
||||
public double FibonacciAverage { get; } // [JsonPropertyName("Fibonacci")]
|
||||
public int? InverseValue { get; } // [JsonPropertyName("InverseValue")]
|
||||
public int ValueMaximum { get; } // [JsonPropertyName("ValueMaximum")]
|
||||
public int ValueMinimum { get; } // [JsonPropertyName("ValueMinimum")]
|
||||
public Notification[] Notifications { get; } // [JsonPropertyName("Notifications")]
|
||||
public int ValueSum { get; } // [JsonPropertyName("ValueSum")]
|
||||
|
||||
private static ReadOnlyDictionary<int, Aggregation> GetKeyValuePairs(Settings settings, Dictionary<int, List<Notification>> keyValuePairs)
|
||||
{
|
||||
Dictionary<int, Aggregation> results = new();
|
||||
int? inverseValue;
|
||||
double inverseAverage;
|
||||
Aggregation aggregation;
|
||||
double fibonacciAverage;
|
||||
List<int> collection = new();
|
||||
int averageFromInverseCeiling;
|
||||
List<int> inverseCollection = new();
|
||||
List<int> fibonacciCollection = new();
|
||||
foreach (KeyValuePair<int, List<Notification>> keyValuePair in keyValuePairs)
|
||||
{
|
||||
collection.Clear();
|
||||
inverseCollection.Clear();
|
||||
fibonacciCollection.Clear();
|
||||
foreach (Notification notification in keyValuePair.Value)
|
||||
{
|
||||
collection.Add(notification.Value);
|
||||
if (notification.Inverse is null)
|
||||
continue;
|
||||
inverseCollection.Add(notification.Inverse.Value);
|
||||
if (notification.Fibonacci is null)
|
||||
continue;
|
||||
fibonacciCollection.Add(notification.Fibonacci.Value);
|
||||
}
|
||||
if (inverseCollection.Count == 0 || fibonacciCollection.Count == 0)
|
||||
continue;
|
||||
inverseAverage = Math.Round(inverseCollection.Average(), settings.Digits);
|
||||
averageFromInverseCeiling = (int)Math.Ceiling(inverseAverage);
|
||||
inverseValue = Notification.GetInverse(averageFromInverseCeiling);
|
||||
fibonacciAverage = Math.Round(fibonacciCollection.Average(), settings.Digits);
|
||||
aggregation = new(inverseAverage: inverseAverage,
|
||||
valueCount: collection.Count,
|
||||
fibonacciAverage: fibonacciAverage,
|
||||
inverseValue: inverseValue,
|
||||
valueMaximum: collection.Max(),
|
||||
valueMinimum: collection.Min(),
|
||||
notifications: keyValuePair.Value.ToArray(),
|
||||
valueSum: collection.Sum());
|
||||
results.Add(keyValuePair.Key, aggregation);
|
||||
}
|
||||
return new(results);
|
||||
}
|
||||
|
||||
private static ReadOnlyCollection<Notification> GetNotifications(Settings settings, string directory)
|
||||
{
|
||||
List<Notification> results = new();
|
||||
string text;
|
||||
string[] files;
|
||||
Notification? notification;
|
||||
List<Notification>? collection;
|
||||
Dictionary<string, List<Notification>> keyValuePairs = new();
|
||||
string[] directories = Directory.GetDirectories(directory, "*", SearchOption.TopDirectoryOnly);
|
||||
foreach (string subDirectory in directories)
|
||||
{
|
||||
keyValuePairs.Clear();
|
||||
files = Directory.GetFiles(subDirectory, settings.SourceFileFilter, SearchOption.TopDirectoryOnly);
|
||||
foreach (string file in files)
|
||||
{
|
||||
text = File.ReadAllText(file);
|
||||
if (string.IsNullOrEmpty(text) || text[0] == '[')
|
||||
continue;
|
||||
notification = JsonSerializer.Deserialize(text, NotificationSourceGenerationContext.Default.Notification);
|
||||
if (notification is null || notification.Id == 0)
|
||||
continue;
|
||||
if (string.IsNullOrEmpty(notification.RemoteIpAddress))
|
||||
continue;
|
||||
if (!keyValuePairs.TryGetValue(notification.RemoteIpAddress, out collection))
|
||||
{
|
||||
keyValuePairs.Add(notification.RemoteIpAddress, new());
|
||||
if (!keyValuePairs.TryGetValue(notification.RemoteIpAddress, out collection))
|
||||
throw new Exception();
|
||||
}
|
||||
collection.Add(notification);
|
||||
}
|
||||
foreach (KeyValuePair<string, List<Notification>> keyValuePair in keyValuePairs)
|
||||
{
|
||||
if (keyValuePair.Value.Count == 1)
|
||||
results.Add(keyValuePair.Value[0]);
|
||||
else
|
||||
{
|
||||
notification = keyValuePair.Value.Select(record => new KeyValuePair<long, Notification>(record.Time, record)).OrderBy(pair => pair.Key).Last().Value;
|
||||
results.Add(notification);
|
||||
}
|
||||
}
|
||||
}
|
||||
return new(results);
|
||||
}
|
||||
|
||||
private static ReadOnlyDictionary<int, Aggregation> GetKeyValuePairs(Settings settings, string directory)
|
||||
{
|
||||
ReadOnlyDictionary<int, Aggregation> results;
|
||||
List<Notification>? collection;
|
||||
Dictionary<int, List<Notification>> keyValuePairs = new();
|
||||
ReadOnlyCollection<Notification> notifications = GetNotifications(settings, directory);
|
||||
foreach (Notification notification in notifications)
|
||||
{
|
||||
if (!keyValuePairs.TryGetValue(notification.Id, out collection))
|
||||
{
|
||||
keyValuePairs.Add(notification.Id, new());
|
||||
if (!keyValuePairs.TryGetValue(notification.Id, out collection))
|
||||
throw new Exception();
|
||||
}
|
||||
collection.Add(notification);
|
||||
}
|
||||
results = GetKeyValuePairs(settings, keyValuePairs);
|
||||
return results;
|
||||
}
|
||||
|
||||
internal static ReadOnlyDictionary<string, ReadOnlyDictionary<int, Aggregation>> GetKeyValuePairsAndWriteFiles(Settings settings)
|
||||
{
|
||||
Dictionary<string, ReadOnlyDictionary<int, Aggregation>> results = new();
|
||||
string json;
|
||||
string jsonOld;
|
||||
string jsonFile;
|
||||
string directoryName;
|
||||
ReadOnlyDictionary<int, Aggregation> keyValuePairs;
|
||||
if (!Directory.Exists(settings.SourceFileLocation))
|
||||
_ = Directory.CreateDirectory(settings.SourceFileLocation);
|
||||
if (!Directory.Exists(settings.TargetFileLocation))
|
||||
_ = Directory.CreateDirectory(settings.TargetFileLocation);
|
||||
string[] directories = Directory.GetDirectories(settings.SourceFileLocation, "*", SearchOption.TopDirectoryOnly);
|
||||
foreach (string directory in directories)
|
||||
{
|
||||
directoryName = Path.GetFileName(directory);
|
||||
keyValuePairs = GetKeyValuePairs(settings, directory);
|
||||
jsonFile = Path.Combine(settings.TargetFileLocation, $"{directoryName}.json");
|
||||
json = JsonSerializer.Serialize(keyValuePairs, AggregationReadOnlyDictionarySourceGenerationContext.Default.ReadOnlyDictionaryInt32Aggregation);
|
||||
// keyValuePairs = JsonSerializer.Deserialize(json, AggregationReadOnlyDictionarySourceGenerationContext.Default.ReadOnlyDictionaryInt32Aggregation);
|
||||
jsonOld = File.Exists(jsonFile) ? File.ReadAllText(jsonFile) : string.Empty;
|
||||
if (json != jsonOld)
|
||||
File.WriteAllText(jsonFile, json);
|
||||
results.Add(directoryName, keyValuePairs);
|
||||
}
|
||||
return new(results);
|
||||
}
|
||||
|
||||
internal static ReadOnlyDictionary<int, Aggregation> GetKeyValuePairs(Settings settings, Notification notification)
|
||||
{
|
||||
ReadOnlyDictionary<int, Aggregation> results;
|
||||
Dictionary<int, List<Notification>> keyValuePairs = new() { { notification.Id, new Notification[] { notification }.ToList() } };
|
||||
results = GetKeyValuePairs(settings, keyValuePairs);
|
||||
return results;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -46,4 +200,10 @@ internal partial class AggregationSourceGenerationContext : JsonSerializerContex
|
||||
[JsonSerializable(typeof(Aggregation[]))]
|
||||
internal partial class AggregationCollectionSourceGenerationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(ReadOnlyDictionary<int, Aggregation>))]
|
||||
internal partial class AggregationReadOnlyDictionarySourceGenerationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
@ -3,28 +3,36 @@ using Adaptation.Ifx.Eaf.EquipmentConnector.File.Configuration;
|
||||
using Adaptation.Shared;
|
||||
using Adaptation.Shared.Duplicator;
|
||||
using Adaptation.Shared.Methods;
|
||||
using log4net;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
|
||||
namespace Adaptation.FileHandlers.Priority;
|
||||
|
||||
#nullable enable
|
||||
|
||||
public class FileRead : Shared.FileRead, IFileRead
|
||||
{
|
||||
|
||||
private readonly Timer _Timer;
|
||||
internal static ILog Log => _Log;
|
||||
internal static Settings Settings => _Settings;
|
||||
internal static Dictionary<int, WorkItem> WorkItems => _WorkItems;
|
||||
#pragma warning disable IDE0032, CS8618
|
||||
private static new ILog _Log;
|
||||
private static Settings _Settings;
|
||||
private static Dictionary<int, WorkItem> _WorkItems;
|
||||
#pragma warning restore IDE0032, CS8618
|
||||
|
||||
public FileRead(ISMTP smtp, Dictionary<string, string> fileParameter, string cellInstanceName, int? connectionCount, string cellInstanceConnectionName, FileConnectorConfiguration fileConnectorConfiguration, string equipmentTypeName, string parameterizedModelObjectDefinitionType, IList<ModelObjectParameterDefinition> modelObjectParameters, string equipmentDictionaryName, Dictionary<string, List<long>> dummyRuns, Dictionary<long, List<string>> staticRuns, bool useCyclicalForDescription, bool isEAFHosted) :
|
||||
base(new Description(), false, smtp, fileParameter, cellInstanceName, connectionCount, cellInstanceConnectionName, fileConnectorConfiguration, equipmentTypeName, parameterizedModelObjectDefinitionType, modelObjectParameters, equipmentDictionaryName, dummyRuns, staticRuns, useCyclicalForDescription, isEAFHosted: connectionCount is null)
|
||||
{
|
||||
_WorkItems = new();
|
||||
_MinFileLength = 10;
|
||||
_NullData = string.Empty;
|
||||
_Logistics = new(this);
|
||||
_NullData = string.Empty;
|
||||
_Log = LogManager.GetLogger(typeof(FileRead));
|
||||
if (_FileParameter is null)
|
||||
throw new Exception(cellInstanceConnectionName);
|
||||
if (_ModelObjectParameterDefinitions is null)
|
||||
@ -33,12 +41,23 @@ public class FileRead : Shared.FileRead, IFileRead
|
||||
throw new Exception(cellInstanceConnectionName);
|
||||
if (_IsEAFHosted)
|
||||
NestExistingFiles(_FileConnectorConfiguration);
|
||||
if (!Debugger.IsAttached && fileConnectorConfiguration.PreProcessingMode != FileConnectorConfiguration.PreProcessingModeEnum.Process)
|
||||
_Timer = new Timer(Callback, null, (int)(fileConnectorConfiguration.FileScanningIntervalInSeconds * 1000), Timeout.Infinite);
|
||||
else
|
||||
string parentDirectory = Path.GetDirectoryName(_FileConnectorConfiguration.TargetFileLocation) ?? throw new Exception();
|
||||
_Settings = new(digits: 5,
|
||||
parentDirectory: parentDirectory,
|
||||
priorities: 3,
|
||||
priorityGroups: 9,
|
||||
sourceFileFilter: _FileConnectorConfiguration.SourceFileFilter,
|
||||
sourceFileLocation: _FileConnectorConfiguration.SourceFileLocation,
|
||||
targetFileLocation: _FileConnectorConfiguration.TargetFileLocation);
|
||||
string? json = WeightedShortestJobFirstHub.PopulatedWorkItemsAndGetJson(_Settings);
|
||||
if (!string.IsNullOrEmpty(json))
|
||||
WeightedShortestJobFirstHub.WriteJson(json);
|
||||
string cellInstanceNamed = string.Concat("CellInstance.", _EquipmentType);
|
||||
string url = GetPropertyValue(cellInstanceConnectionName, modelObjectParameters, $"{cellInstanceNamed}.Microsoft.Owin.Hosting.WebApp.Start.URL");
|
||||
if (_IsEAFHosted)
|
||||
{
|
||||
_Timer = new Timer(Callback, null, Timeout.Infinite, Timeout.Infinite);
|
||||
Callback(null);
|
||||
_ = Microsoft.Owin.Hosting.WebApp.Start(url);
|
||||
_Log.Info($"Server running on {url}");
|
||||
}
|
||||
}
|
||||
|
||||
@ -91,7 +110,7 @@ public class FileRead : Shared.FileRead, IFileRead
|
||||
DateTime dateTime = DateTime.Now;
|
||||
results = GetExtractResult(reportFullPath, dateTime);
|
||||
if (results.Item3 is null)
|
||||
results = new Tuple<string, Test[], JsonElement[], List<FileInfo>>(results.Item1, Array.Empty<Test>(), JsonSerializer.Deserialize<JsonElement[]>("[]"), results.Item4);
|
||||
results = new Tuple<string, Test[], JsonElement[], List<FileInfo>>(results.Item1, Array.Empty<Test>(), JsonSerializer.Deserialize<JsonElement[]>("[]") ?? throw new Exception(), results.Item4);
|
||||
if (results.Item3.Length > 0 && _IsEAFHosted)
|
||||
WritePDSF(this, results.Item3);
|
||||
UpdateLastTicksDuration(DateTime.Now.Ticks - dateTime.Ticks);
|
||||
@ -107,187 +126,6 @@ public class FileRead : Shared.FileRead, IFileRead
|
||||
return results;
|
||||
}
|
||||
|
||||
#nullable enable
|
||||
|
||||
private static ReadOnlyCollection<Record> GetRecords(string directory, string searchPattern)
|
||||
{
|
||||
List<Record> results = new();
|
||||
string text;
|
||||
Record? record;
|
||||
string[] files;
|
||||
List<Record>? collection;
|
||||
Dictionary<string, List<Record>> keyValuePairs = new();
|
||||
string[] directories = Directory.GetDirectories(directory, "*", SearchOption.TopDirectoryOnly);
|
||||
foreach (string subDirectory in directories)
|
||||
{
|
||||
keyValuePairs.Clear();
|
||||
files = Directory.GetFiles(subDirectory, searchPattern, SearchOption.TopDirectoryOnly);
|
||||
foreach (string file in files)
|
||||
{
|
||||
text = File.ReadAllText(file);
|
||||
if (string.IsNullOrEmpty(text) || text[0] == '[')
|
||||
continue;
|
||||
record = JsonSerializer.Deserialize<Record>(text);
|
||||
if (record is null || record.Id == 0)
|
||||
continue;
|
||||
if (!keyValuePairs.TryGetValue(record.RemoteIpAddress, out collection))
|
||||
{
|
||||
keyValuePairs.Add(record.RemoteIpAddress, new());
|
||||
if (!keyValuePairs.TryGetValue(record.RemoteIpAddress, out collection))
|
||||
throw new Exception();
|
||||
}
|
||||
collection.Add(record);
|
||||
}
|
||||
foreach (KeyValuePair<string, List<Record>> keyValuePair in keyValuePairs)
|
||||
{
|
||||
if (keyValuePair.Value.Count == 1)
|
||||
results.Add(keyValuePair.Value[0]);
|
||||
else
|
||||
{
|
||||
record = keyValuePair.Value.Select(record => new KeyValuePair<long, Record>(record.Time, record)).OrderBy(pair => pair.Key).Last().Value;
|
||||
results.Add(record);
|
||||
}
|
||||
}
|
||||
}
|
||||
return new(results);
|
||||
}
|
||||
|
||||
private static int? GetInverse(int value) =>
|
||||
value switch
|
||||
{
|
||||
1 => 3,
|
||||
2 => 2,
|
||||
3 => 1,
|
||||
_ => null
|
||||
};
|
||||
|
||||
private static int? GetInverse(double value)
|
||||
{
|
||||
int? result;
|
||||
if (value > 3)
|
||||
result = null;
|
||||
else if (value > 2)
|
||||
result = 1;
|
||||
else if (value > 1)
|
||||
result = 2;
|
||||
else if (value > 0)
|
||||
result = 3;
|
||||
else
|
||||
result = null;
|
||||
return result;
|
||||
}
|
||||
|
||||
private static ReadOnlyDictionary<int, Aggregation> GetKeyValuePairs(Dictionary<int, List<Record>> keyValuePairs)
|
||||
{
|
||||
Dictionary<int, Aggregation> results = new();
|
||||
Aggregation aggregation;
|
||||
int? inverse;
|
||||
double average;
|
||||
List<int> collection = new();
|
||||
foreach (KeyValuePair<int, List<Record>> keyValuePair in keyValuePairs)
|
||||
{
|
||||
collection.Clear();
|
||||
foreach (Record record in keyValuePair.Value)
|
||||
{
|
||||
inverse = GetInverse(record.Value);
|
||||
if (inverse is null)
|
||||
continue;
|
||||
collection.Add(inverse.Value);
|
||||
}
|
||||
average = collection.Average();
|
||||
inverse = GetInverse(average);
|
||||
aggregation = new(average.ToString("0.000"),
|
||||
keyValuePair.Value.Count,
|
||||
inverse,
|
||||
keyValuePair.Value.Max(record => record.Value),
|
||||
keyValuePair.Value.Min(record => record.Value),
|
||||
new(keyValuePair.Value),
|
||||
keyValuePair.Value.Sum(record => record.Value));
|
||||
results.Add(keyValuePair.Key, aggregation);
|
||||
}
|
||||
return new(results);
|
||||
}
|
||||
|
||||
private static ReadOnlyDictionary<int, Aggregation> GetKeyValuePairs(string directory, string searchPattern)
|
||||
{
|
||||
ReadOnlyDictionary<int, Aggregation> results;
|
||||
List<Record>? collection;
|
||||
Dictionary<int, List<Record>> keyValuePairs = new();
|
||||
ReadOnlyCollection<Record> records = GetRecords(directory, searchPattern);
|
||||
foreach (Record record in records)
|
||||
{
|
||||
if (!keyValuePairs.TryGetValue(record.Id, out collection))
|
||||
{
|
||||
keyValuePairs.Add(record.Id, new());
|
||||
if (!keyValuePairs.TryGetValue(record.Id, out collection))
|
||||
throw new Exception();
|
||||
}
|
||||
collection.Add(record);
|
||||
}
|
||||
results = GetKeyValuePairs(keyValuePairs);
|
||||
return results;
|
||||
}
|
||||
|
||||
private static void WriteFiles(string sourceFileLocation, string sourceFileFilter, string targetFileLocation)
|
||||
{
|
||||
string json;
|
||||
string jsonFile;
|
||||
string directoryName;
|
||||
if (!Directory.Exists(sourceFileLocation))
|
||||
_ = Directory.CreateDirectory(sourceFileLocation);
|
||||
if (!Directory.Exists(targetFileLocation))
|
||||
_ = Directory.CreateDirectory(targetFileLocation);
|
||||
ReadOnlyDictionary<int, Aggregation> keyValuePairs;
|
||||
JsonSerializerOptions jsonSerializerOptions = new() { WriteIndented = true };
|
||||
string[] directories = Directory.GetDirectories(sourceFileLocation, "*", SearchOption.TopDirectoryOnly);
|
||||
foreach (string directory in directories)
|
||||
{
|
||||
directoryName = Path.GetFileName(directory);
|
||||
keyValuePairs = GetKeyValuePairs(directory, sourceFileFilter);
|
||||
jsonFile = Path.Combine(targetFileLocation, $"{directoryName}.json");
|
||||
json = JsonSerializer.Serialize(keyValuePairs, jsonSerializerOptions);
|
||||
File.WriteAllText(jsonFile, json);
|
||||
}
|
||||
}
|
||||
|
||||
private void Callback(object state)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_IsEAFHosted)
|
||||
WriteFiles(_FileConnectorConfiguration.SourceFileLocation, _FileConnectorConfiguration.SourceFileFilter, _FileConnectorConfiguration.TargetFileLocation);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
string subject = string.Concat("Exception:", _CellInstanceConnectionName);
|
||||
string body = string.Concat(exception.Message, Environment.NewLine, Environment.NewLine, exception.StackTrace);
|
||||
try
|
||||
{
|
||||
_SMTP.SendHighPriorityEmailMessage(subject, body);
|
||||
File.WriteAllText(".email", body);
|
||||
}
|
||||
catch (Exception) { }
|
||||
}
|
||||
try
|
||||
{
|
||||
if (_FileConnectorConfiguration?.FileScanningIntervalInSeconds is null)
|
||||
throw new Exception();
|
||||
TimeSpan timeSpan = new(DateTime.Now.AddSeconds(_FileConnectorConfiguration.FileScanningIntervalInSeconds.Value).Ticks - DateTime.Now.Ticks);
|
||||
_ = _Timer.Change((long)timeSpan.TotalMilliseconds, Timeout.Infinite);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
string subject = string.Concat("Exception:", _CellInstanceConnectionName);
|
||||
string body = string.Concat(exception.Message, Environment.NewLine, Environment.NewLine, exception.StackTrace);
|
||||
try
|
||||
{
|
||||
_SMTP.SendHighPriorityEmailMessage(subject, body);
|
||||
File.WriteAllText(".email", body);
|
||||
}
|
||||
catch (Exception) { }
|
||||
}
|
||||
}
|
||||
|
||||
private Tuple<string, Test[], JsonElement[], List<FileInfo>> GetExtractResult(string reportFullPath, DateTime dateTime)
|
||||
{
|
||||
Tuple<string, Test[], JsonElement[], List<FileInfo>> results;
|
||||
|
82
Adaptation/FileHandlers/Priority/Notification.cs
Normal file
82
Adaptation/FileHandlers/Priority/Notification.cs
Normal file
@ -0,0 +1,82 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Adaptation.FileHandlers.Priority;
|
||||
|
||||
#nullable enable
|
||||
|
||||
public class Notification
|
||||
{
|
||||
|
||||
[JsonConstructor]
|
||||
public Notification(int? fibonacci,
|
||||
int id,
|
||||
int? inverse,
|
||||
string page,
|
||||
string? remoteIpAddress,
|
||||
string? site,
|
||||
long time,
|
||||
int value)
|
||||
{
|
||||
int? i = inverse is not null ? inverse : GetInverse(value);
|
||||
Fibonacci = fibonacci is not null ? fibonacci : i is null ? null : GetFibonacci(i.Value);
|
||||
Id = id;
|
||||
Inverse = i;
|
||||
Page = page;
|
||||
RemoteIpAddress = remoteIpAddress is not null ? remoteIpAddress : null;
|
||||
Site = site is not null ? site : "MES";
|
||||
Time = time;
|
||||
Value = value;
|
||||
}
|
||||
|
||||
[JsonPropertyName("id")] public int Id { get; }
|
||||
[JsonPropertyName("fibonacci")] public int? Fibonacci { get; }
|
||||
[JsonPropertyName("inverse")] public int? Inverse { get; }
|
||||
[JsonPropertyName("page")] public string Page { get; }
|
||||
[JsonPropertyName("RemoteIpAddress")] public string? RemoteIpAddress { get; }
|
||||
[JsonPropertyName("site")] public string? Site { get; }
|
||||
[JsonPropertyName("time")] public long Time { get; }
|
||||
[JsonPropertyName("value")] public int Value { get; }
|
||||
|
||||
internal static int? GetInverse(int value) =>
|
||||
value switch
|
||||
{
|
||||
1 => 5,
|
||||
2 => 4,
|
||||
3 => 3,
|
||||
4 => 2,
|
||||
5 => 1,
|
||||
_ => null
|
||||
};
|
||||
|
||||
private static int? GetFibonacci(int value) =>
|
||||
value switch
|
||||
{
|
||||
9 => 55,
|
||||
8 => 34,
|
||||
7 => 21,
|
||||
6 => 13,
|
||||
5 => 8,
|
||||
4 => 5,
|
||||
3 => 3,
|
||||
2 => 2,
|
||||
1 => 1,
|
||||
_ => null
|
||||
};
|
||||
|
||||
internal static Notification GetNotification(Notification notification, string? remoteIpAddress, string? connectionId) =>
|
||||
new(notification.Fibonacci,
|
||||
notification.Id,
|
||||
notification.Inverse,
|
||||
notification.Page,
|
||||
remoteIpAddress ?? connectionId,
|
||||
notification.Site,
|
||||
notification.Time,
|
||||
notification.Value);
|
||||
|
||||
}
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(Notification))]
|
||||
public partial class NotificationSourceGenerationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Adaptation.FileHandlers.Priority;
|
||||
|
||||
public class Record
|
||||
{
|
||||
|
||||
[JsonConstructor]
|
||||
public Record(
|
||||
string json,
|
||||
int id,
|
||||
string page,
|
||||
string queryString,
|
||||
string remoteIpAddress,
|
||||
long time,
|
||||
int value
|
||||
)
|
||||
{
|
||||
Json = json;
|
||||
Id = id;
|
||||
Page = page;
|
||||
QueryString = queryString;
|
||||
RemoteIpAddress = remoteIpAddress;
|
||||
Time = time;
|
||||
Value = value;
|
||||
}
|
||||
|
||||
[JsonPropertyName("Json")] public string Json { get; }
|
||||
[JsonPropertyName("id")] public int Id { get; }
|
||||
[JsonPropertyName("page")] public string Page { get; }
|
||||
[JsonPropertyName("QueryString")] public string QueryString { get; }
|
||||
[JsonPropertyName("RemoteIpAddress")] public string RemoteIpAddress { get; }
|
||||
[JsonPropertyName("time")] public long Time { get; }
|
||||
[JsonPropertyName("value")] public int Value { get; }
|
||||
|
||||
}
|
43
Adaptation/FileHandlers/Priority/Settings.cs
Normal file
43
Adaptation/FileHandlers/Priority/Settings.cs
Normal file
@ -0,0 +1,43 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Adaptation.FileHandlers.Priority;
|
||||
|
||||
#nullable enable
|
||||
|
||||
public class Settings
|
||||
{
|
||||
|
||||
[JsonConstructor]
|
||||
public Settings(int digits,
|
||||
string parentDirectory,
|
||||
int priorities,
|
||||
int priorityGroups,
|
||||
string sourceFileFilter,
|
||||
string sourceFileLocation,
|
||||
string targetFileLocation)
|
||||
{
|
||||
Digits = digits;
|
||||
ParentDirectory = parentDirectory;
|
||||
Priorities = priorities;
|
||||
PriorityGroups = priorityGroups;
|
||||
SourceFileFilter = sourceFileFilter;
|
||||
SourceFileLocation = sourceFileLocation;
|
||||
TargetFileLocation = targetFileLocation;
|
||||
}
|
||||
|
||||
public int Digits { get; } // [JsonPropertyName("Digits")]
|
||||
public string ParentDirectory { get; } // [JsonPropertyName("ParentDirectory")]
|
||||
public int Priorities { get; } // [JsonPropertyName("Priorities")]
|
||||
public int PriorityGroups { get; } // [JsonPropertyName("PriorityGroups")]
|
||||
public string SourceFileFilter { get; } // [JsonPropertyName("SourceFileFilter")]
|
||||
public string SourceFileLocation { get; } // [JsonPropertyName("SourceFileLocation")]
|
||||
public string TargetFileLocation { get; } // [JsonPropertyName("TargetFileLocation")]
|
||||
|
||||
}
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(Dictionary<int, Settings>))]
|
||||
internal partial class SettingsDictionarySourceGenerationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
13
Adaptation/FileHandlers/Priority/Startup.cs
Normal file
13
Adaptation/FileHandlers/Priority/Startup.cs
Normal file
@ -0,0 +1,13 @@
|
||||
using Microsoft.Owin.Cors;
|
||||
using Owin;
|
||||
|
||||
public class Startup
|
||||
{
|
||||
|
||||
public void Configuration(IAppBuilder app)
|
||||
{
|
||||
_ = app.UseCors(CorsOptions.AllowAll);
|
||||
_ = app.MapSignalR();
|
||||
}
|
||||
|
||||
}
|
158
Adaptation/FileHandlers/Priority/WeightedShortestJobFirstHub.cs
Normal file
158
Adaptation/FileHandlers/Priority/WeightedShortestJobFirstHub.cs
Normal file
@ -0,0 +1,158 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Adaptation.FileHandlers.Priority;
|
||||
|
||||
public class WeightedShortestJobFirstHub : Microsoft.AspNet.SignalR.Hub
|
||||
{
|
||||
|
||||
// public async Task Send(int n)
|
||||
// {
|
||||
// await Clients.All.send(n);
|
||||
// }
|
||||
|
||||
private string? GetRemoteIpAddress() =>
|
||||
Context?.Headers?.Get("X-Real-IP");
|
||||
|
||||
public void Send(string name, string message)
|
||||
{
|
||||
Console.WriteLine($"{name}:{message};");
|
||||
// FileRead.Logger.LogWarning($"{name}:{message};");
|
||||
// FileRead.Log?.Info($"{name}:{message};");
|
||||
Console.WriteLine(Context?.ConnectionId);
|
||||
// FileRead.Logger.LogWarning(Context?.ConnectionId);
|
||||
// FileRead.Log?.Info(Context?.ConnectionId);
|
||||
string? remoteIpAddress = GetRemoteIpAddress();
|
||||
Console.WriteLine(remoteIpAddress);
|
||||
// FileRead.Logger.LogWarning(remoteIpAddress);
|
||||
// FileRead.Log?.Info(remoteIpAddress);
|
||||
Clients.All.addMessage(name, message);
|
||||
}
|
||||
|
||||
private static void FileWriteAllText(Settings settings, Notification n)
|
||||
{
|
||||
string json = JsonSerializer.Serialize(n, NotificationSourceGenerationContext.Default.Notification);
|
||||
string directory = Path.Combine(settings.SourceFileLocation, n.Page, n.Id.ToString());
|
||||
if (!Directory.Exists(directory))
|
||||
_ = Directory.CreateDirectory(directory);
|
||||
string checkFile = Path.Combine(directory, $"{n.Time}.json");
|
||||
File.WriteAllText(checkFile, json);
|
||||
}
|
||||
|
||||
internal static void WriteJson(string json)
|
||||
{
|
||||
string jsonFile = Path.Combine(FileRead.Settings.ParentDirectory, "{}.json");
|
||||
string jsonFileWith = Path.Combine(FileRead.Settings.ParentDirectory, "{[]}.json");
|
||||
string jsonOld = File.Exists(jsonFileWith) ? File.ReadAllText(jsonFileWith) : string.Empty;
|
||||
if (json != jsonOld)
|
||||
{
|
||||
File.WriteAllText(jsonFileWith, json);
|
||||
Dictionary<int, WorkItem> w = JsonSerializer.Deserialize(json.Replace($"\"{nameof(Aggregation.Notifications)}\":", "\"ignore\":"), WorkItemDictionarySourceGenerationContext.Default.DictionaryInt32WorkItem) ?? throw new Exception();
|
||||
json = JsonSerializer.Serialize(w, WorkItemDictionarySourceGenerationContext.Default.DictionaryInt32WorkItem);
|
||||
File.WriteAllText(jsonFile, json);
|
||||
}
|
||||
}
|
||||
|
||||
internal static string? PopulatedWorkItemsAndGetJson(Settings settings)
|
||||
{
|
||||
string? result = null;
|
||||
ReadOnlyDictionary<int, WorkItem?> workItems = WorkItem.GetKeyValuePairs(settings);
|
||||
int useCount = (from l in workItems where l.Value.CostOfDelay is not null select true).Count();
|
||||
double prioritySize = useCount / settings.Priorities;
|
||||
double priorityGroupSize = useCount / settings.PriorityGroups;
|
||||
WorkItem[] sorted = (from l in workItems
|
||||
where l.Value is not null
|
||||
orderby l.Value.Site is not null,
|
||||
l.Value.Site descending,
|
||||
l.Value.CostOfDelay is not null,
|
||||
l.Value.CostOfDelay descending,
|
||||
l.Value.BusinessValue?.FibonacciAverage is not null,
|
||||
l.Value.BusinessValue?.FibonacciAverage descending,
|
||||
l.Key
|
||||
select l.Value).ToArray();
|
||||
lock (FileRead.WorkItems)
|
||||
{
|
||||
int j = 0;
|
||||
WorkItem w;
|
||||
double value;
|
||||
int lastId = -1;
|
||||
int? sortBeforeId;
|
||||
WorkItem workItem;
|
||||
int? sortPriority;
|
||||
int? sortPriorityGroup;
|
||||
FileRead.WorkItems.Clear();
|
||||
for (int i = 0; i < sorted.Length; i++)
|
||||
{
|
||||
w = sorted[i];
|
||||
if (w.CostOfDelay is null)
|
||||
{
|
||||
sortBeforeId = null;
|
||||
sortPriority = null;
|
||||
sortPriorityGroup = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
j += 1;
|
||||
sortBeforeId = lastId;
|
||||
value = (j / prioritySize) + 1;
|
||||
sortPriority = (int)Math.Floor(value);
|
||||
if (sortPriority > settings.Priorities)
|
||||
sortPriority = settings.Priorities;
|
||||
value = (j / priorityGroupSize) + 1;
|
||||
sortPriorityGroup = (int)Math.Floor(value);
|
||||
if (sortPriorityGroup > settings.PriorityGroups)
|
||||
sortPriorityGroup = settings.PriorityGroups;
|
||||
}
|
||||
workItem = WorkItem.GetWorkItem(w, i, sortBeforeId, sortPriority, sortPriorityGroup);
|
||||
FileRead.WorkItems.Add(workItem.Id, workItem);
|
||||
lastId = w.Id;
|
||||
}
|
||||
result = JsonSerializer.Serialize(FileRead.WorkItems, WorkItemDictionarySourceGenerationContext.Default.DictionaryInt32WorkItem);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static WorkItem GetWorkItem(Notification notification)
|
||||
{
|
||||
WorkItem? result;
|
||||
lock (FileRead.WorkItems)
|
||||
{
|
||||
if (!FileRead.WorkItems.TryGetValue(notification.Id, out result))
|
||||
throw new Exception();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public void NotifyAll(Notification notification)
|
||||
{
|
||||
try
|
||||
{
|
||||
string? json = null;
|
||||
string? remoteIpAddress = GetRemoteIpAddress();
|
||||
Notification n = Notification.GetNotification(notification, remoteIpAddress, Context?.ConnectionId);
|
||||
Console.WriteLine(n.ToString());
|
||||
// FileRead.Logger.LogWarning(n.ToString());
|
||||
// FileRead.Log?.Info(n.ToString());
|
||||
FileWriteAllText(FileRead.Settings, n);
|
||||
json = PopulatedWorkItemsAndGetJson(FileRead.Settings);
|
||||
if (!string.IsNullOrEmpty(json))
|
||||
WriteJson(json);
|
||||
if (!string.IsNullOrEmpty(n.RemoteIpAddress))
|
||||
{
|
||||
WorkItem workItem = GetWorkItem(n);
|
||||
Clients.All.updateWorkItem(n.Page, workItem);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{ Console.WriteLine($"{ex.Message}{Environment.NewLine}{ex.StackTrace}"); }
|
||||
// { FileRead.Logger.LogError(ex, "Error!"); }
|
||||
// { FileRead.Log?.Error("Error!", ex); }
|
||||
}
|
||||
|
||||
}
|
205
Adaptation/FileHandlers/Priority/WorkItem.cs
Normal file
205
Adaptation/FileHandlers/Priority/WorkItem.cs
Normal file
@ -0,0 +1,205 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Adaptation.FileHandlers.Priority;
|
||||
|
||||
#nullable enable
|
||||
|
||||
public class WorkItem
|
||||
{
|
||||
|
||||
[JsonConstructor]
|
||||
public WorkItem(double? costOfDelay,
|
||||
Aggregation? businessValue,
|
||||
Aggregation? effort,
|
||||
int id,
|
||||
int? sortBeforeId,
|
||||
int? sortPriority,
|
||||
int? sortPriorityGroup,
|
||||
Aggregation? riskReductionOpportunityEnablement,
|
||||
string? site,
|
||||
int? sortOrder,
|
||||
Aggregation? timeCriticality,
|
||||
double? weightedShortestJobFirst)
|
||||
{
|
||||
CostOfDelay = costOfDelay;
|
||||
BusinessValue = businessValue;
|
||||
Effort = effort;
|
||||
Id = id;
|
||||
Site = site;
|
||||
SortBeforeId = sortBeforeId;
|
||||
SortPriority = sortPriority;
|
||||
SortPriorityGroup = sortPriorityGroup;
|
||||
RiskReductionOpportunityEnablement = riskReductionOpportunityEnablement;
|
||||
SortOrder = sortOrder;
|
||||
TimeCriticality = timeCriticality;
|
||||
WeightedShortestJobFirst = weightedShortestJobFirst;
|
||||
}
|
||||
|
||||
const string _PageEffort = "effort";
|
||||
const string _PageTimeCriticality = "time";
|
||||
const string _PageBusinessValue = "business";
|
||||
const string _PageRiskReductionOpportunityEnablement = "risk";
|
||||
|
||||
public double? CostOfDelay { get; } // [JsonPropertyName("CostOfDelay")]
|
||||
public Aggregation? BusinessValue { get; } // [JsonPropertyName("BusinessValue")]
|
||||
public Aggregation? Effort { get; } // [JsonPropertyName("Effort")]
|
||||
public int Id { get; } // [JsonPropertyName("Id")]
|
||||
public string? Site { get; } // [JsonPropertyName("Site")]
|
||||
public int? SortBeforeId { get; } // [JsonPropertyName("SortBeforeId")]
|
||||
public int? SortPriority { get; } // [JsonPropertyName("SortPriority")]
|
||||
public int? SortPriorityGroup { get; } // [JsonPropertyName("SortPriorityGroup")]
|
||||
public Aggregation? RiskReductionOpportunityEnablement { get; } // [JsonPropertyName("RiskReductionOpportunityEnablement")]
|
||||
public int? SortOrder { get; } // [JsonPropertyName("SortOrder")]
|
||||
public Aggregation? TimeCriticality { get; } // [JsonPropertyName("TimeCriticality")]
|
||||
public double? WeightedShortestJobFirst { get; } // [JsonPropertyName("WeightedShortestJobFirst")]
|
||||
|
||||
internal static WorkItem GetWorkItem(WorkItem workItem, int i, int? sortBeforeId, int? sortPriority, int? sortPriorityGroup) =>
|
||||
new(workItem.CostOfDelay,
|
||||
workItem.BusinessValue,
|
||||
workItem.Effort,
|
||||
workItem.Id,
|
||||
sortBeforeId,
|
||||
sortPriority,
|
||||
sortPriorityGroup,
|
||||
workItem.RiskReductionOpportunityEnablement,
|
||||
workItem.Site,
|
||||
i,
|
||||
workItem.TimeCriticality,
|
||||
workItem.WeightedShortestJobFirst);
|
||||
|
||||
private static string? GetSite(Aggregation? effort, Aggregation? businessValue, Aggregation? timeCriticality, Aggregation? riskReductionOpportunityEnablement)
|
||||
{
|
||||
string? result = null;
|
||||
if (result is null && effort is not null)
|
||||
{
|
||||
foreach (Notification notification in effort.Notifications)
|
||||
{
|
||||
if (notification.Site is not null)
|
||||
{
|
||||
result = notification.Site;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (result is null && businessValue is not null)
|
||||
{
|
||||
foreach (Notification notification in businessValue.Notifications)
|
||||
{
|
||||
if (notification.Site is not null)
|
||||
{
|
||||
result = notification.Site;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (result is null && timeCriticality is not null)
|
||||
{
|
||||
foreach (Notification notification in timeCriticality.Notifications)
|
||||
{
|
||||
if (notification.Site is not null)
|
||||
{
|
||||
result = notification.Site;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (result is null && riskReductionOpportunityEnablement is not null)
|
||||
{
|
||||
foreach (Notification notification in riskReductionOpportunityEnablement.Notifications)
|
||||
{
|
||||
if (notification.Site is not null)
|
||||
{
|
||||
result = notification.Site;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static ReadOnlyDictionary<int, WorkItem?> GetWorkItems(Settings settings, ReadOnlyDictionary<string, ReadOnlyDictionary<int, Aggregation>> keyValuePairs)
|
||||
{
|
||||
Dictionary<int, WorkItem?> results = new();
|
||||
string? site;
|
||||
WorkItem? workItem;
|
||||
double? costOfDelay;
|
||||
Aggregation? effort;
|
||||
List<int> ids = new();
|
||||
Aggregation? businessValue;
|
||||
Aggregation? timeCriticality;
|
||||
double? weightedShortestJobFirst;
|
||||
Aggregation? riskReductionOpportunityEnablement;
|
||||
Dictionary<int, Aggregation?> effortCollection = new();
|
||||
Dictionary<int, Aggregation?> businessValueCollection = new();
|
||||
Dictionary<int, Aggregation?> timeCriticalityCollection = new();
|
||||
Dictionary<int, Aggregation?> riskReductionOpportunityEnablementCollection = new();
|
||||
foreach (KeyValuePair<string, ReadOnlyDictionary<int, Aggregation>> keyValuePair in keyValuePairs)
|
||||
{
|
||||
foreach (KeyValuePair<int, Aggregation> keyValue in keyValuePair.Value)
|
||||
{
|
||||
if (!ids.Contains(keyValue.Key))
|
||||
ids.Add(keyValue.Key);
|
||||
if (keyValuePair.Key == _PageEffort)
|
||||
effortCollection.Add(keyValue.Key, keyValue.Value);
|
||||
else if (keyValuePair.Key == _PageTimeCriticality)
|
||||
timeCriticalityCollection.Add(keyValue.Key, keyValue.Value);
|
||||
else if (keyValuePair.Key == _PageBusinessValue)
|
||||
businessValueCollection.Add(keyValue.Key, keyValue.Value);
|
||||
else if (keyValuePair.Key == _PageRiskReductionOpportunityEnablement)
|
||||
riskReductionOpportunityEnablementCollection.Add(keyValue.Key, keyValue.Value);
|
||||
else
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
foreach (int id in ids)
|
||||
{
|
||||
if (!effortCollection.TryGetValue(id, out effort))
|
||||
effort = null;
|
||||
if (!businessValueCollection.TryGetValue(id, out businessValue))
|
||||
businessValue = null;
|
||||
if (!timeCriticalityCollection.TryGetValue(id, out timeCriticality))
|
||||
timeCriticality = null;
|
||||
if (!riskReductionOpportunityEnablementCollection.TryGetValue(id, out riskReductionOpportunityEnablement))
|
||||
riskReductionOpportunityEnablement = null;
|
||||
site = GetSite(effort, businessValue, timeCriticality, riskReductionOpportunityEnablement);
|
||||
costOfDelay = businessValue is null
|
||||
|| timeCriticality is null
|
||||
|| riskReductionOpportunityEnablement is null ? null : businessValue.FibonacciAverage
|
||||
+ timeCriticality.FibonacciAverage
|
||||
+ riskReductionOpportunityEnablement.FibonacciAverage;
|
||||
weightedShortestJobFirst = costOfDelay is null || effort is null ? null : Math.Round(costOfDelay.Value / effort.FibonacciAverage, settings.Digits);
|
||||
workItem = new(costOfDelay: costOfDelay,
|
||||
businessValue: businessValue,
|
||||
effort: effort,
|
||||
id: id,
|
||||
sortBeforeId: null,
|
||||
sortPriority: null,
|
||||
sortPriorityGroup: null,
|
||||
riskReductionOpportunityEnablement: riskReductionOpportunityEnablement,
|
||||
site: site,
|
||||
sortOrder: null,
|
||||
timeCriticality: timeCriticality,
|
||||
weightedShortestJobFirst: weightedShortestJobFirst);
|
||||
results.Add(id, workItem);
|
||||
}
|
||||
return new(results);
|
||||
}
|
||||
|
||||
internal static ReadOnlyDictionary<int, WorkItem?> GetKeyValuePairs(Settings settings)
|
||||
{
|
||||
ReadOnlyDictionary<int, WorkItem?> results;
|
||||
ReadOnlyDictionary<string, ReadOnlyDictionary<int, Aggregation>> keyValuePairs = Aggregation.GetKeyValuePairsAndWriteFiles(settings);
|
||||
results = GetWorkItems(settings, keyValuePairs);
|
||||
return results;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(Dictionary<int, WorkItem>))]
|
||||
internal partial class WorkItemDictionarySourceGenerationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
@ -37,13 +37,27 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.3" />
|
||||
<PackageReference Include="FFMpegCore" Version="5.1.0" />
|
||||
<PackageReference Include="IKVM.AWT.WinForms" Version="7.2.4630.5"><NoWarn>NU1701</NoWarn></PackageReference>
|
||||
<PackageReference Include="IKVM.OpenJDK.Core" Version="7.2.4630.5"><NoWarn>NU1701</NoWarn></PackageReference>
|
||||
<PackageReference Include="IKVM.OpenJDK.Media" Version="7.2.4630.5"><NoWarn>NU1701</NoWarn></PackageReference>
|
||||
<PackageReference Include="IKVM.OpenJDK.Text" Version="7.2.4630.5"><NoWarn>NU1701</NoWarn></PackageReference>
|
||||
<PackageReference Include="IKVM.OpenJDK.Util" Version="7.2.4630.5"><NoWarn>NU1701</NoWarn></PackageReference>
|
||||
<PackageReference Include="IKVM.OpenJDK.XML.API" Version="7.2.4630.5"><NoWarn>NU1701</NoWarn></PackageReference>
|
||||
<PackageReference Include="IKVM.Runtime" Version="7.2.4630.5"><NoWarn>NU1701</NoWarn></PackageReference>
|
||||
<PackageReference Include="IKVM.AWT.WinForms" Version="7.2.4630.5">
|
||||
<NoWarn>NU1701</NoWarn>
|
||||
</PackageReference>
|
||||
<PackageReference Include="IKVM.OpenJDK.Core" Version="7.2.4630.5">
|
||||
<NoWarn>NU1701</NoWarn>
|
||||
</PackageReference>
|
||||
<PackageReference Include="IKVM.OpenJDK.Media" Version="7.2.4630.5">
|
||||
<NoWarn>NU1701</NoWarn>
|
||||
</PackageReference>
|
||||
<PackageReference Include="IKVM.OpenJDK.Text" Version="7.2.4630.5">
|
||||
<NoWarn>NU1701</NoWarn>
|
||||
</PackageReference>
|
||||
<PackageReference Include="IKVM.OpenJDK.Util" Version="7.2.4630.5">
|
||||
<NoWarn>NU1701</NoWarn>
|
||||
</PackageReference>
|
||||
<PackageReference Include="IKVM.OpenJDK.XML.API" Version="7.2.4630.5">
|
||||
<NoWarn>NU1701</NoWarn>
|
||||
</PackageReference>
|
||||
<PackageReference Include="IKVM.Runtime" Version="7.2.4630.5">
|
||||
<NoWarn>NU1701</NoWarn>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Instances" Version="3.0.1" />
|
||||
<PackageReference Include="log4net" Version="3.0.3"></PackageReference>
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="9.0.0" />
|
||||
@ -60,7 +74,9 @@
|
||||
<PackageReference Include="Microsoft.Win32.SystemEvents" Version="9.0.0" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="3.7.0" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="3.7.0" />
|
||||
<PackageReference Include="Pdfbox" Version="1.1.1"><NoWarn>NU1701</NoWarn></PackageReference>
|
||||
<PackageReference Include="Pdfbox" Version="1.1.1">
|
||||
<NoWarn>NU1701</NoWarn>
|
||||
</PackageReference>
|
||||
<PackageReference Include="RoboSharp" Version="1.6.0" />
|
||||
<PackageReference Include="System.Configuration.ConfigurationManager" Version="9.0.0" />
|
||||
<PackageReference Include="System.Data.OleDb" Version="9.0.0" />
|
||||
@ -78,7 +94,9 @@
|
||||
<PackageReference Include="Microsoft.TeamFoundationServer.Client" Version="16.205.1" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Infineon.Mesa.PDF.Text.Stripper" Version="4.8.0.1"><NoWarn>NU1701</NoWarn></PackageReference>
|
||||
<PackageReference Include="Infineon.Mesa.PDF.Text.Stripper" Version="4.8.0.1">
|
||||
<NoWarn>NU1701</NoWarn>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Infineon.Yoda.DotNetCore" Version="5.4.3" />
|
||||
@ -87,6 +105,15 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Tesseract" Version="5.2.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNet.SignalR" Version="2.4.3" />
|
||||
<PackageReference Include="Microsoft.AspNet.SignalR.Core" Version="2.4.3" />
|
||||
<PackageReference Include="Microsoft.Owin" Version="4.2.2" />
|
||||
<PackageReference Include="Microsoft.Owin.Cors" Version="4.2.2" />
|
||||
<PackageReference Include="Microsoft.Owin.Hosting" Version="4.2.2" />
|
||||
<PackageReference Include="Microsoft.Owin.Security" Version="4.2.2" />
|
||||
<PackageReference Include="Owin" Version="1.0.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="appsettings.json">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
|
@ -87,5 +87,18 @@ public class MESAFIBACKLOG : EAFLoggingUnitTesting
|
||||
EAFLoggingUnitTesting.Logger.LogInformation(string.Concat(methodBase.Name, " - Exit"));
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
[Ignore]
|
||||
#endif
|
||||
[TestMethod]
|
||||
public void Development__v2_58_0__MESAFIBACKLOG__Priority()
|
||||
{
|
||||
string check = "*.json";
|
||||
MethodBase methodBase = new StackFrame().GetMethod();
|
||||
EAFLoggingUnitTesting.Logger.LogInformation(string.Concat(methodBase.Name, " - Getting configuration"));
|
||||
_ = AdaptationTesting.GetWriteConfigurationGetFileRead(methodBase, check, EAFLoggingUnitTesting.AdaptationTesting);
|
||||
EAFLoggingUnitTesting.Logger.LogInformation(string.Concat(methodBase.Name, " - Exit"));
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
@ -1,5 +1,6 @@
|
||||
#if true
|
||||
using Adaptation.FileHandlers.json.WorkItems;
|
||||
using Adaptation.FileHandlers.Priority;
|
||||
using Adaptation.Shared;
|
||||
using Adaptation.Shared.Methods;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
@ -173,8 +174,8 @@ public class MESAFIBACKLOG
|
||||
{
|
||||
string check = "*.json";
|
||||
bool validatePDSF = false;
|
||||
_MESAFIBACKLOG.Development__v2_58_0__MESAFIBACKLOG__ADO();
|
||||
MethodBase methodBase = new StackFrame().GetMethod();
|
||||
_MESAFIBACKLOG.Development__v2_58_0__MESAFIBACKLOG__ADO();
|
||||
Assert.IsFalse(string.IsNullOrEmpty(_MESAFIBACKLOG.AdaptationTesting.TestContext.FullyQualifiedTestClassName));
|
||||
string[] variables = _MESAFIBACKLOG.AdaptationTesting.GetVariables(methodBase, check, validatePDSF);
|
||||
IFileRead fileRead = _MESAFIBACKLOG.AdaptationTesting.Get(methodBase, sourceFileLocation: variables[2], sourceFileFilter: variables[3], useCyclicalForDescription: false);
|
||||
@ -185,5 +186,35 @@ public class MESAFIBACKLOG
|
||||
NonThrowTryCatch();
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
[Ignore]
|
||||
#endif
|
||||
[TestMethod]
|
||||
public void Development__v2_58_0__MESAFIBACKLOG__Priority638323658386612552__Normal()
|
||||
{
|
||||
string check = "*.json";
|
||||
bool validatePDSF = false;
|
||||
MethodBase methodBase = new StackFrame().GetMethod();
|
||||
_MESAFIBACKLOG.Development__v2_58_0__MESAFIBACKLOG__Priority();
|
||||
Assert.IsFalse(string.IsNullOrEmpty(_MESAFIBACKLOG.AdaptationTesting.TestContext.FullyQualifiedTestClassName));
|
||||
string[] variables = _MESAFIBACKLOG.AdaptationTesting.GetVariables(methodBase, check, validatePDSF);
|
||||
IFileRead fileRead = _MESAFIBACKLOG.AdaptationTesting.Get(methodBase, sourceFileLocation: variables[2], sourceFileFilter: variables[3], useCyclicalForDescription: false);
|
||||
Tuple<string, Test[], JsonElement[], List<FileInfo>> extractResult = fileRead.ReExtract();
|
||||
Assert.IsFalse(string.IsNullOrEmpty(extractResult?.Item1));
|
||||
Assert.IsNotNull(extractResult.Item3);
|
||||
Assert.IsNotNull(extractResult.Item4);
|
||||
WeightedShortestJobFirstHub weightedShortestJobFirstHub = new();
|
||||
Notification notification = new(fibonacci: null,
|
||||
id: 1107438888,
|
||||
inverse: null,
|
||||
page: "effort",
|
||||
remoteIpAddress: "10.95.36.87",
|
||||
site: "MES",
|
||||
time: 1737573418926,
|
||||
value: 1);
|
||||
weightedShortestJobFirstHub.NotifyAll(notification);
|
||||
NonThrowTryCatch();
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
@ -150,7 +150,11 @@
|
||||
<Compile Include="Adaptation\FileHandlers\OpenInsightMetrologyViewerAttachments\FileRead.cs" />
|
||||
<Compile Include="Adaptation\FileHandlers\Priority\Aggregation.cs" />
|
||||
<Compile Include="Adaptation\FileHandlers\Priority\FileRead.cs" />
|
||||
<Compile Include="Adaptation\FileHandlers\Priority\Record.cs" />
|
||||
<Compile Include="Adaptation\FileHandlers\Priority\Notification.cs" />
|
||||
<Compile Include="Adaptation\FileHandlers\Priority\Settings.cs" />
|
||||
<Compile Include="Adaptation\FileHandlers\Priority\Startup.cs" />
|
||||
<Compile Include="Adaptation\FileHandlers\Priority\WeightedShortestJobFirstHub.cs" />
|
||||
<Compile Include="Adaptation\FileHandlers\Priority\WorkItem.cs" />
|
||||
<Compile Include="Adaptation\FileHandlers\Processed\FileRead.cs" />
|
||||
<Compile Include="Adaptation\FileHandlers\SPaCe\FileRead.cs" />
|
||||
<Compile Include="Adaptation\Ifx\Eaf\Common\Configuration\ConnectionSetting.cs" />
|
||||
@ -209,6 +213,27 @@
|
||||
<PackageReference Include="Infineon.EAF.Runtime">
|
||||
<Version>2.58.0</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.AspNet.SignalR.SelfHost">
|
||||
<Version>2.4.3</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.AspNet.SignalR.Core">
|
||||
<Version>2.4.3</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Owin">
|
||||
<Version>1.0.0</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.Owin">
|
||||
<Version>2.1.0</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.Owin.Cors">
|
||||
<Version>2.1.0</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.Owin.Security">
|
||||
<Version>2.1.0</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.Owin.Hosting">
|
||||
<Version>2.1.0</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.TeamFoundationServer.Client">
|
||||
<Version>16.205.1</Version>
|
||||
</PackageReference>
|
||||
|
Loading…
x
Reference in New Issue
Block a user