using System;
using System.IO;
using System.Runtime.InteropServices.ComTypes;
using System.Text.Json;
using System.Text.Json.Nodes;
using Config.Net.Core;
namespace Config.Net.Stores
{
///
/// Simple JSON storage using System.Text.Json
///
public class JsonConfigStore : IConfigStore
{
private readonly string? _pathName;
private JsonNode? _j;
///
/// Create JSON storage in the file specified in .
///
/// Name of the file, either path to JSON storage file, or json file content.
/// Set to true if specifies file name, otherwise false.
/// is null.
/// Provided path is not valid.
/// Storage file does not have to exist, however it will be created as soon as first write performed.
public JsonConfigStore(string name, bool isFilePath)
{
if (name == null) throw new ArgumentNullException(nameof(name));
if (isFilePath)
{
_pathName = Path.GetFullPath(name); // Allow relative path to JSON file
_j = ReadJsonFile(_pathName);
}
else
{
_j = ReadJsonString(name);
}
}
public void Dispose()
{
// nothing to dispose.
}
public static string Name => "json";
public bool CanRead => true;
public bool CanWrite => _pathName != null;
public string? Read(string rawKey)
{
if (string.IsNullOrEmpty(rawKey) || _j == null) return null;
bool isLength = OptionPath.TryStripLength(rawKey, out string? key);
if (key == null) return null;
string[] parts = key.Split('.');
if (parts.Length == 0) return null;
JsonNode? node = _j;
foreach (string rawPart in parts)
{
bool isIndex = OptionPath.TryStripIndex(rawPart, out string? part, out int partIndex);
if (part == null) return null;
node = node![part];
if (node == null) return null;
if (isIndex)
{
if (node is not JsonArray ja) return null;
if (partIndex < ja.Count)
{
node = ja[partIndex];
}
else
return null;
}
}
if (isLength)
return node is JsonArray ja ? ja.Count.ToString() : null;
return node!.ToString();
}
public void Write(string key, string? value)
{
if (string.IsNullOrEmpty(_pathName))
throw new InvalidOperationException("please specify file name for writeable config");
if (_j == null) _j = new JsonObject();
// navigate to target element, create if needed
string[] parts = key.Split('.');
if (parts.Length == 0) return;
JsonNode? node = _j;
string? lastPart = null;
foreach (string rawPart in parts)
{
bool isIndex = OptionPath.TryStripIndex(rawPart, out string? part, out int partIndex);
if (part == null) return;
lastPart = part;
JsonNode? nextNode = node[part];
if (isIndex)
{
throw new NotImplementedException();
}
else
{
if (nextNode == null)
{
//create missing node
nextNode = new JsonObject();
node[part] = nextNode;
}
}
node = nextNode;
}
JsonObject? parent = node.Parent as JsonObject;
parent!.Remove(lastPart!);
parent![lastPart!] = JsonValue.Create(value);
string js = _j.ToJsonString(new JsonSerializerOptions { WriteIndented = true });
FileInfo file = new(_pathName);
if (file is not null)
{
if (file.Directory is not null)
{
file.Directory.Create();
}
}
File.WriteAllText(_pathName, js);
}
private static JsonNode? ReadJsonFile(string fileName)
{
if (File.Exists(fileName))
{
string json = File.ReadAllText(fileName);
return ReadJsonString(json);
}
return null;
}
private static JsonNode? ReadJsonString(string jsonString)
{
return JsonNode.Parse(jsonString);
}
}
}