refactored File, Path and Directory usages into FileUtil and cleaned up logs

This commit is contained in:
Alex
2025-01-14 11:42:27 +00:00
parent a615e82086
commit 7ff822be0f
9 changed files with 81 additions and 145 deletions
+10 -7
View File
@@ -14,16 +14,19 @@ public class ConfigServer
{
protected ILogger _logger;
protected JsonUtil _jsonUtil;
protected FileUtil _fileUtil;
protected Dictionary<string, object> configs = new();
protected readonly string[] acceptableFileExtensions = [".json", ".jsonc"];
protected readonly string[] acceptableFileExtensions = ["json", "jsonc"];
public ConfigServer(
ILogger logger,
JsonUtil jsonUtil
JsonUtil jsonUtil,
FileUtil fileUtil
)
{
_logger = logger;
_jsonUtil = jsonUtil;
_fileUtil = fileUtil;
Initialize();
}
@@ -45,13 +48,13 @@ public class ConfigServer
// Get all filepaths
var filepath = "./assets/configs/";
var files = Directory.GetFiles(filepath);
var files = _fileUtil.GetFiles(filepath);
// Add file content to result
foreach (var file in files)
if (acceptableFileExtensions.Contains(Path.GetExtension(file)))
if (acceptableFileExtensions.Contains(_fileUtil.GetFileExtension(file)))
{
var fileContent = File.ReadAllText(file);
var fileContent = _fileUtil.ReadFile(file);
var type = GetConfigTypeByFilename(file);
var deserializedContent = _jsonUtil.Deserialize(fileContent, type);
@@ -61,7 +64,7 @@ public class ConfigServer
throw new Exception($"Server will not run until the: {file} config error mentioned above is fixed");
}
configs[$"spt-{Path.GetFileNameWithoutExtension(file)}"] = deserializedContent;
configs[$"spt-{_fileUtil.StripExtension(file)}"] = deserializedContent;
}
/** TODO: deal with this:
@@ -77,7 +80,7 @@ public class ConfigServer
private Type GetConfigTypeByFilename(string filename)
{
var type = Enum.GetValues<ConfigTypes>()
.First(en => en.GetValue().Contains(Path.GetFileNameWithoutExtension(filename)));
.First(en => en.GetValue().Contains(_fileUtil.StripExtension(filename)));
return type.GetConfigType();
}
}
+39 -13
View File
@@ -1,10 +1,8 @@
using System.Text.Json;
using Core.Annotations;
using Core.Utils;
using Core.Utils;
using Core.Utils.Extensions;
namespace Core.Services;
[Injectable(InjectionType.Singleton)]
public class I18nService
{
private List<string> _locales;
@@ -12,29 +10,39 @@ public class I18nService
private string _defaultLocale;
private string _directory;
private JsonUtil _jsonUtil;
private FileUtil _fileUtil;
private string _setLocale;
private Dictionary<string, Dictionary<string, string>> _loadedLocales = new();
public I18nService(JsonUtil jsonUtil, List<string> locales, Dictionary<string, string> fallbacks, string defaultLocale, string directory)
public I18nService(
FileUtil fileUtil,
JsonUtil jsonUtil,
List<string> locales,
Dictionary<string, string> fallbacks,
string defaultLocale,
string directory
)
{
_locales = locales;
_fallbacks = fallbacks;
_defaultLocale = defaultLocale;
_directory = directory;
_jsonUtil = jsonUtil;
_fileUtil = fileUtil;
Initialize();
}
private void Initialize()
{
var files = Directory.GetFiles(_directory, "*.json");
if (files.Length == 0)
var files = _fileUtil.GetFiles(_directory, true).Where(f => _fileUtil.GetFileExtension(f) == "json").ToList();
if (files.Count == 0)
throw new Exception($"Localisation files in directory {_directory} not found.");
foreach (var file in files)
_loadedLocales.Add(Path.GetFileNameWithoutExtension(file),
_jsonUtil.Deserialize<Dictionary<string, string>>(File.ReadAllText(file)) ?? new Dictionary<string, string>());
_loadedLocales.Add(_fileUtil.StripExtension(file),
_jsonUtil.Deserialize<Dictionary<string, string>>(_fileUtil.ReadFile(file)) ??
new Dictionary<string, string>());
if (!_loadedLocales.ContainsKey(_defaultLocale))
throw new Exception($"The default locale '{_defaultLocale}' does not exist on the loaded locales.");
@@ -53,7 +61,8 @@ public class I18nService
{
var foundFallbackLocale = fallback.First().Value;
if (!_loadedLocales.ContainsKey(foundFallbackLocale))
throw new Exception($"Locale '{locale}' was not defined, and the found fallback locale did not match any of the loaded locales.");
throw new Exception(
$"Locale '{locale}' was not defined, and the found fallback locale did not match any of the loaded locales.");
_setLocale = foundFallbackLocale;
}
@@ -75,9 +84,26 @@ public class I18nService
return value;
}
public string GetLocalised(string key, params object[] args)
public string GetLocalised(string key, object? args)
{
// TODO: Deal with arguments
return GetLocalised(key);
var rawLocalizedString = GetLocalised(key);
if (args == null)
return rawLocalizedString;
if (args is string value)
{
return rawLocalizedString.Replace("%s", value);
}
else
{
foreach (var propertyInfo in args.GetType().GetProperties())
{
var localizedName = $"{{{{{propertyInfo.GetJsonName()}}}}}";
if (rawLocalizedString.Contains(localizedName))
{
rawLocalizedString.Replace(localizedName, propertyInfo.GetValue(args, null)?.ToString() ?? string.Empty);
}
}
return rawLocalizedString;
}
}
}
+3 -1
View File
@@ -19,7 +19,8 @@ public class LocalisationService
RandomUtil randomUtil,
DatabaseServer databaseServer,
LocaleService localeService,
JsonUtil jsonUtil
JsonUtil jsonUtil,
FileUtil fileUtil
)
{
_logger = logger;
@@ -27,6 +28,7 @@ public class LocalisationService
_databaseServer = databaseServer;
_localeService = localeService;
_i18nService = new I18nService(
fileUtil,
jsonUtil,
localeService.GetServerSupportedLocales(),
localeService.GetLocaleFallbacks(),
+5
View File
@@ -25,6 +25,11 @@ public class FileUtil
return Path.GetExtension(path).Replace(".", "");
}
public string GetFileName(string path)
{
return Path.GetFileName(path);
}
public string StripExtension(string path, bool keepPath = false)
{
return keepPath ? path.Split('.').First() : Path.GetFileNameWithoutExtension(path);
+6 -119
View File
@@ -43,18 +43,16 @@ public class ImporterUtil
foreach (var file in files)
{
if (_fileUtil.GetFileExtension(file) != "json") continue;
if (filesToIgnore.Contains(Path.GetFileName(file).ToLower())) continue;
if (filesToIgnore.Contains(_fileUtil.GetFileName(file).ToLower())) continue;
tasks.Add(
Task.Factory.StartNew(() =>
{
// const filename = this.vfs.stripExtension(file);
// const filePathAndName = `${filepath}${file}`;
var fileData = File.ReadAllText(file);
var fileData = _fileUtil.ReadFile(file);
if (onReadCallback != null)
onReadCallback(file, fileData);
var setMethod = GetSetMethod(
Path.GetFileNameWithoutExtension(file).ToLower(),
_fileUtil.StripExtension(file).ToLower(),
loadedType,
out var propertyType,
out var isDictionary
@@ -66,7 +64,7 @@ public class ImporterUtil
onObjectDeserialized(file, fileDeserialized);
setMethod.Invoke(result,
isDictionary ? [Path.GetFileNameWithoutExtension(file), fileDeserialized] : [fileDeserialized]);
isDictionary ? [_fileUtil.StripExtension(file), fileDeserialized] : [fileDeserialized]);
}
catch (Exception e)
{
@@ -116,124 +114,13 @@ public class ImporterUtil
{
var matchedProperty = type.GetProperties()
.FirstOrDefault(prop =>
prop.Name.ToLower() == Path.GetFileNameWithoutExtension(propertyName).ToLower());
prop.Name.ToLower() == _fileUtil.StripExtension(propertyName).ToLower());
if (matchedProperty == null)
throw new Exception(
$"Unable to find property '{Path.GetFileNameWithoutExtension(propertyName)}' for type '{type.Name}'");
$"Unable to find property '{_fileUtil.StripExtension(propertyName)}' for type '{type.Name}'");
propertyType = matchedProperty.PropertyType;
setMethod = matchedProperty.GetSetMethod();
}
return setMethod;
}
/**
* Load files into js objects recursively (synchronous)
* @param filepath Path to folder with files
* @returns
*/
public object LoadRecursive(
string filepath,
Type loadedType,
Action<string, string>? onReadCallback = null,
Action<string, object>? onObjectDeserialized = null
)
{
var result = Activator.CreateInstance(loadedType);
// get all filepaths
var files = Directory.GetFiles(filepath);
var directories = Directory.GetDirectories(filepath);
foreach (var file in files)
if (Path.GetExtension(file) == "json")
{
// const filename = this.vfs.stripExtension(file);
// const filePathAndName = `${filepath}${file}`;
var fileData = File.ReadAllText(file);
onReadCallback(file, fileData);
var matchedProperty = loadedType.GetProperties()
.FirstOrDefault(prop => prop.Name.ToLower() == Path.GetFileNameWithoutExtension(file).ToLower());
if (matchedProperty == null)
throw new Exception($"Unable to find property '{Path.GetFileNameWithoutExtension(file)}' for type '{loadedType.Name}'");
var propertyType = matchedProperty.PropertyType;
var fileDeserialized = _jsonUtil.Deserialize(fileData, propertyType);
onObjectDeserialized(file, fileDeserialized);
matchedProperty.GetSetMethod().Invoke(result, [fileDeserialized]);
}
// deep tree search
foreach (var directory in directories)
{
var matchedProperty = loadedType.GetProperties().FirstOrDefault(prop => prop.Name.ToLower() == directory.ToLower());
if (matchedProperty == null)
throw new Exception($"Unable to find property '{directory}' for type '{loadedType.Name}'");
matchedProperty.GetSetMethod().Invoke(result, [LoadRecursive($"{filepath}{directory}/", matchedProperty.PropertyType)]);
}
// return the result of all async fetch
return result;
}
public async Task<object> LoadAsync(
string filepath,
Type loadedType,
string strippablePath = "",
Action<string, string>? onReadCallback = null,
Action<string, object>? onObjectDeserialized = null
)
{
var result = Activator.CreateInstance(loadedType);
var promises = new List<Task<object>>();
var filesToProcess = new Queue<string>(_fileUtil.GetFiles(filepath, true));
while (filesToProcess.Count != 0)
{
var fileNode = filesToProcess.Dequeue();
if (fileNode == null || _fileUtil.GetFileExtension(fileNode) != "json") continue;
promises.Add(File.ReadAllTextAsync(fileNode).ContinueWith(fd =>
{
onReadCallback(fileNode, fd.Result);
return _jsonUtil.Deserialize(fd.Result, typeof(object));
}));
/*
this.vfs
.readFileAsync(filePathAndName)
.then(async (fileData) => {
onReadCallback(filePathAndName, fileData);
return this.jsonUtil.deserializeWithCacheCheckAsync<any>(fileData, filePathAndName);
})
.then(async (fileDeserialized) => {
onObjectDeserialized(filePathAndName, fileDeserialized);
const strippedFilePath = this.vfs.stripExtension(filePathAndName).replace(filepath, "");
this.placeObject(fileDeserialized, strippedFilePath, result, strippablePath);
})
.then(() => progressWriter.increment()),
);*/
}
//await JSType.Promise<>.all(promises).catch((e) => console.error(e));
return result;
}
/*
protected placeObject<T>(fileDeserialized: any, strippedFilePath: string, result: T, strippablePath: string): void {
const strippedFinalPath = strippedFilePath.replace(strippablePath, "");
let temp = result;
const propertiesToVisit = strippedFinalPath.split("/");
for (let i = 0; i < propertiesToVisit.length; i++) {
const property = propertiesToVisit[i];
if (i === propertiesToVisit.length - 1) {
temp[property] = fileDeserialized;
} else {
if (!temp[property]) {
temp[property] = {};
}
temp = temp[property];
}
}
}*/
}
+2 -1
View File
@@ -14,7 +14,8 @@ public abstract class AbstractFormatter : ITextFormatter
var logLevel = logEvent.Level.ToString().ToUpper().Substring(0, 4);
var message = logEvent.RenderMessage();
var exception = logEvent.Exception != null ? $"{newLine}{logEvent.Exception}{newLine}{logEvent.Exception.StackTrace}" : "";
var logMessage = ProcessText($"[{timestamp} {logLevel}] {message}{exception}");
var sourceContext = logEvent.Properties["SourceContext"].ToString().Replace("\"", "");
var logMessage = ProcessText($"[{timestamp} {logLevel}][{sourceContext}] {message}{exception}");
output.WriteLine(logMessage);
}
}
+3 -1
View File
@@ -8,6 +8,7 @@ using Core.Models.Spt.Config;
using Core.Servers;
using Core.Utils;
using Serilog;
using Serilog.Events;
namespace Server;
@@ -18,7 +19,7 @@ public static class Program
var assemblies = ModDllLoader.LoadAllMods();
HarmonyBootstrapper.LoadAllPatches(assemblies);
var builder = WebApplication.CreateBuilder(args);
builder.Configuration.AddJsonFile("appsettings.json", true, true);
CreateAndRegisterLogger(builder);
@@ -64,6 +65,7 @@ public static class Program
builder.Logging.ClearProviders();
var logger = new LoggerConfiguration()
.ReadFrom.Configuration(builder.Configuration)
.MinimumLevel.Override("Microsoft.AspNetCore.Hosting.Diagnostics", LogEventLevel.Warning)
.CreateLogger();
builder.Logging.AddSerilog(logger);
}
+1
View File
@@ -19,6 +19,7 @@
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.0"/>
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.0"/>
<PackageReference Include="Serilog.AspNetCore" Version="9.0.0" />
<PackageReference Include="Serilog.Expressions" Version="5.0.0" />
<PackageReference Include="Serilog.Sinks.Async" Version="2.1.0" />
</ItemGroup>
+12 -3
View File
@@ -1,9 +1,10 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
"Default": "Trace",
"System": "Information",
"Microsoft": "Information",
"Microsoft.AspNetCore.Hosting.Diagnostics": "Warning"
}
},
"Serilog": {
@@ -31,6 +32,14 @@
]
}
}
],
"Filter": [
{
"Name": "ByExcluding",
"Args": {
"expression": "StartsWith(SourceContext, 'TADAADA')"
}
}
]
}
}