2026-06-05 13:44:39 +09:00

170 lines
5.7 KiB
C#

using Aurora;
using Aurora.Api;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reactive.Linq;
using System.Text;
using System.Threading.Tasks;
using WeldingCommon.Data;
using WeldingCommon.Devices;
using WeldingCommon.Settings;
using WeldingCommon.Utils;
using WeldingCommon.Utils.Diff;
namespace WeldingCommon.Recipes
{
public class RecipeChangeHistoryHandler
{
protected Logger Log = new Logger("RchHandler", "RecipeChangeHistory_Evnet");
protected IAuroraEnvironment _aurora;
protected IRecipeEntry _recipeEntry;
protected SystemParameter _settingParameter;
protected readonly object _historyLock = new object();
public ObservableCollection<RecipeHistory> HistoryDatas { get; set; } = new ObservableCollection<RecipeHistory>();
private string _currentDateKey; // yyyyMMdd
private string GetDateKey(DateTime t) => t.ToString("yyyyMMdd", CultureInfo.InvariantCulture);
private string GetDailyFilePath(string dateKey)
{
var dir = _settingParameter.RecipeHistoryFolderPath;
if (!string.IsNullOrEmpty(dir))
Directory.CreateDirectory(dir);
return Path.Combine(dir, $"RecipeInfo_{dateKey}.ndjson");
}
public void RegistryDeviceHandler(IAuroraEnvironment aurora)
{
_aurora = aurora;
_recipeEntry = aurora.RecipeManager;
_settingParameter = _aurora.SettingEntry[CommonSettingIds.SystemParameter] as SystemParameter;
EnsureDailyContext(DateTime.Now);
}
public void AppendChangedItem(string recipeName, ObservableCollection<PropertyDiff> diffs)
{
lock (_historyLock) {
var now = DateTime.Now;
EnsureDailyContext(now);
var item = new RecipeHistory {
Timestamp = now,
RecipeName = recipeName,
Changes = diffs.Select(d => d.ToString()).ToList()
};
HistoryDatas.Add(item);
AppendNdjsonLine(GetDailyFilePath(_currentDateKey), item);
}
}
private void EnsureDailyContext(DateTime today)
{
var key = GetDateKey(today);
if (_currentDateKey == key)
return;
_currentDateKey = key;
HistoryDatas.Clear();
var path = GetDailyFilePath(key);
LoadNdjson(path, HistoryDatas);
}
private void AppendNdjsonLine(string path, RecipeHistory item)
{
var json = JsonConvert.SerializeObject(item);
using (var fs = new FileStream(path, FileMode.Append, FileAccess.Write, FileShare.ReadWrite)) {
using (var sw = new StreamWriter(fs, new UTF8Encoding(encoderShouldEmitUTF8Identifier: true))) {
sw.WriteLine(json);
}
}
}
private void LoadNdjson(string path, ObservableCollection<RecipeHistory> target)
{
if (!File.Exists(path))
return;
using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) {
using (var sr = new StreamReader(fs, new UTF8Encoding(encoderShouldEmitUTF8Identifier: true))) {
string line;
while ((line = sr.ReadLine()) != null) {
if (string.IsNullOrWhiteSpace(line))
continue;
try {
var item = JsonConvert.DeserializeObject<RecipeHistory>(line);
if (item != null)
target.Add(item);
} catch {
}
}
}
}
}
public ObservableCollection<RecipeHistory> FromStartToEndHistory(DateTime start, DateTime end)
{
if (end < start) {
var tmp = start;
start = end;
end = tmp;
}
var result = new List<RecipeHistory>();
var day = start.Date;
var lastDay = end.Date;
lock (_historyLock) {
while (day <= lastDay) {
var key = GetDateKey(day);
var path = GetDailyFilePath(key);
if (File.Exists(path)) {
using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
using (var sr = new StreamReader(fs, new UTF8Encoding(encoderShouldEmitUTF8Identifier: true))) {
string line;
while ((line = sr.ReadLine()) != null) {
if (string.IsNullOrWhiteSpace(line))
continue;
try {
var item = JsonConvert.DeserializeObject<RecipeHistory>(line);
if (item == null)
continue;
//if (item.Timestamp >= start && item.Timestamp <= end)
result.Add(item);
} catch {
}
}
}
}
day = day.AddDays(1);
}
var ordered = result.OrderByDescending(x => x.Timestamp);
return new ObservableCollection<RecipeHistory>(ordered);
}
}
}
}