met08awct/Adaptation/FileHandlers/wc/WaferCounterHelper.cs
2024-04-02 10:39:16 -07:00

332 lines
12 KiB
C#

using Adaptation.Ifx.Eaf.EquipmentConnector.File.Configuration;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net.WebSockets;
using System.Text;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
namespace Adaptation.FileHandlers.wc;
public class WaferCounterHelper
{
#nullable enable
private class Record
{
public int Check { get; set; }
public int Total { get; set; }
public string? SlotMap { get; set; }
}
private class WaferCounter
{
public DateTime DateTime { get; set; }
public string? DateTimeFormatted { get; set; }
public string? EquipmentId { get; set; }
public string? Text { get; set; }
public int Total { get; set; }
public string? SlotMap { get; set; }
}
private static long? _Wait;
private static string? _Directory;
private static readonly Dictionary<string, ClientWebSocket> _ClientWebSockets = new();
internal static void Initialize(FileConnectorConfiguration fileConnectorConfiguration)
{
_Directory = fileConnectorConfiguration.TargetFileLocation;
_Wait = fileConnectorConfiguration.IdleEventWaitTimeInSeconds;
}
internal static string[] Review()
{
List<string> results = new();
lock (_ClientWebSockets)
{
foreach (KeyValuePair<string, ClientWebSocket> keyValuePair in _ClientWebSockets)
{
if (results.Contains(keyValuePair.Key))
continue;
results.Add(keyValuePair.Key);
}
}
return results.ToArray();
}
internal static void Subscribe(string callbackUrl)
{
if (!_ClientWebSockets.ContainsKey(callbackUrl))
{
ClientWebSocket clientWebSocket = new();
Task task = clientWebSocket.ConnectAsync(new Uri(callbackUrl), CancellationToken.None);
task.Wait();
lock (_ClientWebSockets)
_ClientWebSockets.Add(callbackUrl, clientWebSocket);
}
}
private static void CloseAndDispose(string callbackUrl, ClientWebSocket clientWebSocket)
{
Task task = clientWebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None);
task.Wait();
clientWebSocket.Dispose();
lock (_ClientWebSockets)
_ = _ClientWebSockets.Remove(callbackUrl);
}
internal static void Unsubscribe(string callbackUrl)
{
if (_ClientWebSockets.TryGetValue(callbackUrl, out ClientWebSocket? clientWebSocket))
CloseAndDispose(callbackUrl, clientWebSocket);
}
private static Record GetRecord(string line1, string line2)
{
Record result;
string? slotMap = string.IsNullOrEmpty(line2) || line2.Length != 8 ? null : line2.Substring(1, 1);
int check = slotMap == "1" ? 1 : 0;
int total = int.Parse(line1.Substring(1));
foreach (char item in line2.Substring(2))
{
switch (item)
{
case '0':
check += 0;
slotMap += "0000";
break;
case '1':
check += 1;
slotMap += "0001";
break;
case '2':
check += 1;
slotMap += "0010";
break;
case '3':
check += 2;
slotMap += "0011";
break;
case '4':
check += 1;
slotMap += "0100";
break;
case '5':
check += 2;
slotMap += "0101";
break;
case '6':
check += 2;
slotMap += "0110";
break;
case '7':
check += 3;
slotMap += "0111";
break;
case '8':
check += 1;
slotMap += "1000";
break;
case '9':
check += 2;
slotMap += "1001";
break;
case 'A':
check += 2;
slotMap += "1010";
break;
case 'B':
check += 3;
slotMap += "1011";
break;
case 'C':
check += 2;
slotMap += "1100";
break;
case 'D':
check += 3;
slotMap += "1101";
break;
case 'E':
check += 3;
slotMap += "1110";
break;
case 'F':
check += 4;
slotMap += "1111";
break;
default:
break;
}
}
result = new Record { Check = check, Total = total, SlotMap = slotMap };
return result;
}
internal static void TestSlotMap(string line1, string line2, string expectedSlotMap)
{
Record record = GetRecord(line1, line2);
if (record.SlotMap != expectedSlotMap)
throw new NotSupportedException($"{line1}{line2}{expectedSlotMap}");
}
internal static string GetJson(string cellInstanceName, DateTime dateTime, string contents)
{
string result;
string[] separator = new string[] { "\r\n" };
string[] lines = contents.Split(separator, StringSplitOptions.None);
if (lines.Length <= 1)
throw new Exception("Incomplete file length!");
Record record = GetRecord(lines[0], lines[1]);
if (string.IsNullOrEmpty(record.SlotMap) || record.SlotMap.Length != 25)
throw new Exception("Wrong length!");
if (record.Total != record.Check)
throw new Exception("Invalid!");
WaferCounter waferCounter = new()
{
DateTime = dateTime,
DateTimeFormatted = dateTime.ToString("yyyy-MM-dd hh:mm tt"),
EquipmentId = cellInstanceName,
Text = contents,
Total = record.Total,
SlotMap = record.SlotMap
};
result = JsonSerializer.Serialize(waferCounter);
return result;
}
private static void Notify(string json, List<KeyValuePair<string, ClientWebSocket>> clientWebSockets)
{
List<KeyValuePair<string, ClientWebSocket>> removeClientWebSockets = new();
ArraySegment<byte> bytes = new(Encoding.Default.GetBytes(json));
foreach (KeyValuePair<string, ClientWebSocket> clientWebSocket in clientWebSockets)
{
try
{
Task task = clientWebSocket.Value.SendAsync(bytes, WebSocketMessageType.Binary, false, CancellationToken.None);
task.Wait();
}
catch (Exception)
{
removeClientWebSockets.Add(clientWebSocket);
}
}
if (removeClientWebSockets.Count > 0)
{
lock (_ClientWebSockets)
{
foreach (KeyValuePair<string, ClientWebSocket> clientWebSocket in removeClientWebSockets)
CloseAndDispose(clientWebSocket.Key, clientWebSocket.Value);
}
}
}
private static void Archive(FileConnectorConfiguration fileConnectorConfiguration, Calendar calendar, DateTime dateTime, string fileName, string fullFileName)
{
string weekOfYear = $"{dateTime:yyyy}_Week_{calendar.GetWeekOfYear(dateTime, CalendarWeekRule.FirstDay, DayOfWeek.Sunday):00}";
string archiveDirectory = Path.Combine(fileConnectorConfiguration.TargetFileLocation, "Archive", weekOfYear);
if (!Directory.Exists(archiveDirectory))
_ = Directory.CreateDirectory(archiveDirectory);
string to = Path.Combine(archiveDirectory, fileName);
File.Move(fullFileName, to);
}
private static void MoveFile(string waferSizeDirectory, FileInfo fileInfo)
{
Calendar calendar = new CultureInfo("en-US").Calendar;
string weekOfYear = $"{fileInfo.LastWriteTime:yyyy}_Week_{calendar.GetWeekOfYear(fileInfo.LastWriteTime, CalendarWeekRule.FirstDay, DayOfWeek.Sunday):00}";
string checkDirectory = Path.Combine(waferSizeDirectory, "Archive", weekOfYear);
if (!Directory.Exists(checkDirectory))
_ = Directory.CreateDirectory(checkDirectory);
string checkFile = Path.Combine(checkDirectory, fileInfo.Name);
if (!File.Exists(checkFile))
File.Move(fileInfo.FullName, checkFile);
}
internal static void Notify(FileConnectorConfiguration fileConnectorConfiguration, Calendar calendar, DateTime dateTime, string fileName, string fullFileName, string json)
{
List<KeyValuePair<string, ClientWebSocket>> clientWebSockets = new();
lock (_ClientWebSockets)
{
foreach (KeyValuePair<string, ClientWebSocket> keyValuePair in _ClientWebSockets)
clientWebSockets.Add(keyValuePair);
}
if (clientWebSockets.Count > 0)
{
Notify(json, clientWebSockets);
Archive(fileConnectorConfiguration, calendar, dateTime, fileName, fullFileName);
}
}
private static FileInfo[] GetFileInfoCollection(string waferSizeDirectory)
{
List<FileInfo> results = new();
List<string> files = new();
FileInfo[] fileInfoCollection;
DateTime dateTime = DateTime.Now;
long ticks = dateTime.AddSeconds(1).Ticks;
for (int i = 0; i < int.MaxValue; i++)
{
files.AddRange(!Directory.Exists(waferSizeDirectory) ? Array.Empty<string>() : Directory.GetFiles(waferSizeDirectory, "*.wc", SearchOption.TopDirectoryOnly));
if (results.Count > 0 || DateTime.Now.Ticks > ticks)
break;
Thread.Sleep(250);
}
fileInfoCollection = (from l in files select new FileInfo(l)).OrderByDescending(l => l.LastWriteTime).ToArray();
if (fileInfoCollection.Length > 0)
results.Add(fileInfoCollection[0]);
for (int i = 0; i < fileInfoCollection.Length; i++)
MoveFile(waferSizeDirectory, fileInfoCollection[i]);
return fileInfoCollection;
}
private static WaferCounter GetLastQuantityAndSlotMapWithText(string waferSize, string text, FileInfo fileInfo)
{
WaferCounter result;
string[] lines = File.ReadAllLines(fileInfo.FullName);
if (lines.Length <= 1)
throw new Exception("Incomplete file length!");
string[] segments = fileInfo.Name.Split('-');
Record record = GetRecord(lines[0], lines[1]);
string equipmentId = segments.Length < 2 ? fileInfo.Name : segments[1].Split('.')[0];
if (string.IsNullOrEmpty(record.SlotMap) || record.SlotMap.Length != 25)
throw new Exception("Wrong length!");
if (record.Total != record.Check)
throw new Exception("Invalid!");
result = new()
{
DateTime = fileInfo.LastWriteTime,
DateTimeFormatted = fileInfo.LastWriteTime.ToString("yyyy-MM-dd hh:mm tt"),
EquipmentId = $"WC{waferSize}{equipmentId}",
Text = text,
Total = record.Total,
SlotMap = record.SlotMap
};
return result;
}
private static string GetWaferSizeDirectory(string area, string waferSize) =>
Path.Combine(_Directory, area, waferSize);
internal static string GetLastQuantityAndSlotMap(string area, string waferSize)
{
string result;
WaferCounter waferCounter;
string waferSizeDirectory = GetWaferSizeDirectory(area, waferSize);
FileInfo[] fileInfoCollection = GetFileInfoCollection(waferSizeDirectory);
if (fileInfoCollection.Length == 0)
throw new Exception("No files!");
string text = string.Empty;
waferCounter = GetLastQuantityAndSlotMapWithText(waferSize, text, fileInfoCollection[0]);
result = JsonSerializer.Serialize(waferCounter);
return result;
}
}