Files
2026-07-13 13:13:17 +08:00

203 lines
6.2 KiB
C#

#nullable enable
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using Newtonsoft.Json;
using T3.Core.Compilation;
using T3.Core.Logging;
namespace T3.Core.Settings;
/// <summary>
/// A currently meek attempt at centralizing user data in a folder outside of the application or project folders.
/// Settings, logs, backups, variations, etc should be stored in this folder.
/// Also refers to "SettingsFolderInApplicationDirectory", which is used for defaults
/// Todo: should variations be included in project folders? Probably not, but we should think about how to best preserve and update them.
/// </summary>
public static class UserData
{
static UserData()
{
Directory.CreateDirectory(FileLocations.ReadOnlySettingsPath);
Directory.CreateDirectory(FileLocations.SettingsDirectory);
}
public static bool TryLoadOrInitializeUserData<T>(string relativeFilePath, [NotNullWhen(true)] out T? result)
{
result = default;
if (!TryLoadingOrWriteDefaults(relativeFilePath, out var jsonString))
return false;
try
{
result = JsonConvert.DeserializeObject<T>(jsonString);
return result != null;
}
catch (Exception)
{
return false;
}
}
/// <summary>
/// Returns the content of the settings file if it exists. Otherwise, initialize the file with content of default.
/// </summary>
/// <summary>
/// Loads user data from the user folder, falling back to the defaults folder.
/// Does NOT copy the default into the user folder — use this for read-only loads
/// like applying a layout on F1.
/// </summary>
public static bool TryLoading(string relativeFilePath, out string fileText)
{
var filePath = GetFilePath(relativeFilePath, UserDataLocation.User);
if (File.Exists(filePath))
{
try
{
fileText = File.ReadAllText(filePath);
return true;
}
catch
{
Log.Info($"User data file {filePath} could not be loaded.");
}
}
var defaultsFilePath = GetFilePath(relativeFilePath, UserDataLocation.Defaults);
if (File.Exists(defaultsFilePath))
{
try
{
fileText = File.ReadAllText(defaultsFilePath);
return true;
}
catch (Exception e)
{
Log.Info($"User data file {defaultsFilePath} could not be loaded. Error: {e}");
}
}
fileText = string.Empty;
return false;
}
public static bool TryLoadingOrWriteDefaults(string relativeFilePath, out string fileText)
{
var filePath = GetFilePath(relativeFilePath, UserDataLocation.User);
if (File.Exists(filePath))
{
try
{
fileText = File.ReadAllText(filePath);
return true;
}
catch
{
Log.Info($"User data file {filePath} could not be loaded.");
}
}
var defaultsFilePath = GetFilePath(relativeFilePath, UserDataLocation.Defaults);
if (File.Exists(defaultsFilePath))
{
try
{
fileText = File.ReadAllText(defaultsFilePath);
try
{
var directory = Path.GetDirectoryName(filePath);
Directory.CreateDirectory(directory!);
File.WriteAllText(filePath, fileText);
}
catch (Exception e)
{
Log.Error($"User data file {filePath} could not be saved. Error: {e}");
}
return true;
}
catch (Exception e)
{
Log.Info($"User data file {defaultsFilePath} could not be loaded. Error: {e}");
}
}
fileText = string.Empty;
return false;
}
private static string GetFilePath(string relativeFilePath, UserDataLocation location)
{
var filePath = Path.Combine(location == UserDataLocation.User
? FileLocations.SettingsDirectory
: FileLocations.DefaultsSourcePath, relativeFilePath);
return filePath;
}
public static bool TrySave(string relativeFilePath, string fileContent, UserDataLocation location = UserDataLocation.User)
{
var filePath = GetFilePath(relativeFilePath, location);
var directory = Path.GetDirectoryName(filePath);
Directory.CreateDirectory(directory!);
try
{
File.WriteAllText(filePath, fileContent);
return true;
}
catch (Exception e)
{
Log.Error($"Failed to save file {filePath}: {e}");
return false;
}
}
private static bool CanLoad(string relativeFileName, UserDataLocation location, out string filePath)
{
filePath = GetFilePath(relativeFileName, location);
return File.Exists(filePath);
}
public static bool TryLoad(string relativeFilePath, UserDataLocation location, out string fileContent, out string filePath)
{
var canLoad = CanLoad(relativeFilePath, location, out filePath);
if (!canLoad)
{
fileContent = string.Empty;
return false;
}
try
{
fileContent = File.ReadAllText(filePath);
return true;
}
catch
{
Log.Info($"User data file {filePath} could not be loaded.");
fileContent = string.Empty;
return false;
}
}
public static bool CanLoad(string relativeFileName)
{
var filePath = Path.Combine(FileLocations.SettingsDirectory, relativeFileName);
if (File.Exists(filePath))
{
return true;
}
var defaultsFilePath = Path.Combine(FileLocations.ReadOnlySettingsPath, relativeFileName);
return File.Exists(defaultsFilePath);
}
public enum UserDataLocation
{
Defaults,
User
}
}