262 lines
11 KiB
C#
262 lines
11 KiB
C#
using log4net;
|
|
using Nancy;
|
|
using Nancy.Extensions;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Collections.ObjectModel;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text.Json;
|
|
|
|
#nullable enable
|
|
|
|
#pragma warning disable CA1822
|
|
|
|
namespace Adaptation.FileHandlers.Priority;
|
|
|
|
public class WeightedShortestJobFirstModule : NancyModule
|
|
{
|
|
|
|
public WeightedShortestJobFirstModule()
|
|
{
|
|
Get("/api/v1/ado/", _ =>
|
|
{
|
|
string json;
|
|
ILog log = LogManager.GetLogger(typeof(WeightedShortestJobFirstModule));
|
|
log.Info($"Enter-{nameof(GetKeyValuePairs)}");
|
|
try
|
|
{
|
|
string query = Request.Url.Query;
|
|
IDictionary<string, IEnumerable<string>> collection = Nancy.Helpers.HttpUtility.ParseQueryString(query).ToDictionary();
|
|
KeyValuePair<string, WorkItem>? workItem = GetWorkItem(collection);
|
|
json = workItem is null ? string.Empty : JsonSerializer.Serialize(workItem, KeyValuePairStringWorkItemSourceGenerationContext.Default.KeyValuePairStringWorkItem);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
log.Fatal($"Exception-{nameof(GetKeyValuePairs)}{Environment.NewLine}{ex.Message}{Environment.NewLine}{Environment.NewLine}{ex.StackTrace}");
|
|
throw;
|
|
}
|
|
log.Info($"Return-{nameof(GetKeyValuePairs)}");
|
|
return json;
|
|
});
|
|
base.Post("/api/v1/ado/", _ =>
|
|
{
|
|
Notification notification;
|
|
ILog log = LogManager.GetLogger(typeof(WeightedShortestJobFirstModule));
|
|
log.Info($"Enter-{nameof(Post)}");
|
|
try
|
|
{
|
|
string body = Request.Body.AsString();
|
|
DynamicDictionary form = Request.Form;
|
|
Dictionary<string, object> keyValuePairs = form.ToDictionary();
|
|
notification = GetNotification(body, keyValuePairs);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
log.Fatal($"Exception-{nameof(Post)}{Environment.NewLine}{ex.Message}{Environment.NewLine}{Environment.NewLine}{ex.StackTrace}");
|
|
throw;
|
|
}
|
|
log.Info($"Return-{nameof(Post)}");
|
|
return notification.Time.ToString();
|
|
});
|
|
}
|
|
|
|
private static Dictionary<string, string?> GetKeyValuePairs(IDictionary<string, IEnumerable<string>> collection)
|
|
{
|
|
Dictionary<string, string?> results = new();
|
|
string[] array;
|
|
foreach (KeyValuePair<string, IEnumerable<string>> keyValuePair in collection)
|
|
{
|
|
array = keyValuePair.Value.ToArray();
|
|
if (array.Length != 1)
|
|
continue;
|
|
if (array.Length == 1 && array[0] == "null")
|
|
results.Add(keyValuePair.Key, null);
|
|
else
|
|
results.Add(keyValuePair.Key, array[0]);
|
|
}
|
|
return results;
|
|
}
|
|
|
|
internal static Notification GetNotification(string body, Dictionary<string, object> keyValuePairs)
|
|
{
|
|
Notification result;
|
|
if (FileRead.Queue is null)
|
|
throw new NullReferenceException(nameof(FileRead.Queue));
|
|
if (FileRead.Settings is null)
|
|
throw new NullReferenceException(nameof(FileRead.Settings));
|
|
if (FileRead.WorkItems is null)
|
|
throw new NullReferenceException(nameof(FileRead.WorkItems));
|
|
string? json;
|
|
if (!string.IsNullOrEmpty(body) && body[0] == '{')
|
|
{
|
|
File.WriteAllText(".json", body);
|
|
result = JsonSerializer.Deserialize(body, NotificationSourceGenerationContext.Default.Notification) ?? throw new NullReferenceException();
|
|
}
|
|
else
|
|
{
|
|
json = JsonSerializer.Serialize(keyValuePairs);
|
|
File.WriteAllText(".json", json);
|
|
result = JsonSerializer.Deserialize(json, NotificationSourceGenerationContext.Default.Notification) ?? throw new NullReferenceException();
|
|
}
|
|
if (!string.IsNullOrEmpty(result.Id))
|
|
FileWriteAllText(FileRead.Settings, result);
|
|
json = PopulatedWorkItemsAndGetJson(FileRead.Settings, FileRead.WorkItems);
|
|
if (!string.IsNullOrEmpty(json))
|
|
WriteJson(FileRead.Settings, json);
|
|
if (!string.IsNullOrEmpty(result.SessionId))
|
|
{
|
|
string key = GetKey(result);
|
|
Queue<KeyValuePair<string, WorkItem>>? queue;
|
|
lock (FileRead.Queue)
|
|
{
|
|
if (!FileRead.Queue.TryGetValue(key, out queue))
|
|
{
|
|
FileRead.Queue.Add(key, new());
|
|
if (!FileRead.Queue.TryGetValue(key, out queue))
|
|
throw new Exception();
|
|
}
|
|
}
|
|
WorkItem? workItem = GetWorkItem(FileRead.WorkItems, result);
|
|
if (workItem is not null)
|
|
{
|
|
lock (FileRead.Queue)
|
|
{
|
|
foreach (KeyValuePair<string, Queue<KeyValuePair<string, WorkItem>>> keyValuePair in FileRead.Queue)
|
|
keyValuePair.Value.Enqueue(new(result.Page, workItem));
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
internal static KeyValuePair<string, WorkItem>? GetWorkItem(IDictionary<string, IEnumerable<string>> collection)
|
|
{
|
|
KeyValuePair<string, WorkItem>? result;
|
|
Dictionary<string, string?> keyValuePairs = GetKeyValuePairs(collection);
|
|
Notification notification = Notification.Get(keyValuePairs);
|
|
if (FileRead.Queue is null)
|
|
result = null;
|
|
else
|
|
{
|
|
Queue<KeyValuePair<string, WorkItem>>? queue;
|
|
string key = GetKey(notification);
|
|
lock (FileRead.Queue)
|
|
{
|
|
if (!FileRead.Queue.TryGetValue(key, out queue))
|
|
{
|
|
FileRead.Queue.Add(key, new());
|
|
if (!FileRead.Queue.TryGetValue(key, out queue))
|
|
throw new Exception();
|
|
}
|
|
result = queue.Count == 0 ? null : queue.Dequeue();
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private static string GetKey(Notification notification) =>
|
|
$"{notification.SessionId}-{notification.MachineId}-{notification.Username}";
|
|
|
|
private static void FileWriteAllText(Settings settings, Notification notification)
|
|
{
|
|
if (string.IsNullOrEmpty(notification.Id))
|
|
throw new NullReferenceException(nameof(notification.Id));
|
|
string json = JsonSerializer.Serialize(notification, NotificationSourceGenerationContext.Default.Notification);
|
|
string directory = Path.Combine(settings.SourceFileLocation, notification.Page, notification.Id.ToString());
|
|
if (!Directory.Exists(directory))
|
|
_ = Directory.CreateDirectory(directory);
|
|
string checkFile = Path.Combine(directory, $"{notification.Time}.json");
|
|
File.WriteAllText(checkFile, json);
|
|
}
|
|
|
|
internal static string? PopulatedWorkItemsAndGetJson(Settings settings, Dictionary<int, WorkItem> workItems)
|
|
{
|
|
string? result = null;
|
|
ReadOnlyDictionary<int, WorkItem?> keyValuePairs = WorkItem.GetKeyValuePairs(settings);
|
|
int useCount = (from l in keyValuePairs 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 keyValuePairs
|
|
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 (workItems)
|
|
{
|
|
int j = 0;
|
|
WorkItem w;
|
|
double value;
|
|
int lastId = -1;
|
|
int? sortBeforeId;
|
|
WorkItem workItem;
|
|
int? sortPriority;
|
|
workItems.Clear();
|
|
int? sortPriorityGroup;
|
|
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);
|
|
workItems.Add(workItem.Id, workItem);
|
|
lastId = w.Id;
|
|
}
|
|
result = JsonSerializer.Serialize(workItems, WorkItemDictionarySourceGenerationContext.Default.DictionaryInt32WorkItem);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private static WorkItem? GetWorkItem(Dictionary<int, WorkItem> workItems, Notification notification)
|
|
{
|
|
WorkItem? result;
|
|
if (string.IsNullOrEmpty(notification.Id) || !int.TryParse(notification.Id, out int id))
|
|
result = null;
|
|
else
|
|
{
|
|
lock (workItems)
|
|
{
|
|
if (!workItems.TryGetValue(id, out result))
|
|
throw new Exception();
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
internal static void WriteJson(Settings settings, string json)
|
|
{
|
|
string jsonFile = Path.Combine(settings.ParentDirectory, "{}.json");
|
|
string jsonFileWith = Path.Combine(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);
|
|
}
|
|
}
|
|
|
|
} |