Initial commit

This commit is contained in:
2026-07-03 16:37:12 +07:00
commit 63b8c1ea8b
1931 changed files with 640587 additions and 0 deletions

View File

@@ -0,0 +1,281 @@
using RobotNet10.CustomConfiguration.Models;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace RobotNet10.CustomConfiguration.Helpers;
/// <summary>
/// Helper class cho parse và serialize JSON config files
/// Format JSON mới: Object với metadata và variables
/// Format: {"id": "guid", "configType": "...", "createdAt": "...", "updatedAt": "...", "description": "...", "variables": [...]}
/// </summary>
public static class JsonConfigParser
{
private static readonly JsonSerializerOptions JsonOptions = new()
{
Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
PropertyNameCaseInsensitive = true,
DefaultIgnoreCondition = JsonIgnoreCondition.Never,
WriteIndented = true
};
/// <summary>
/// Parse JSON stream thành ConfigFile (format mới với metadata)
/// </summary>
public static ConfigFile ParseConfigFile(Stream jsonStream)
{
using var reader = new StreamReader(jsonStream);
var json = reader.ReadToEnd();
return ParseConfigFile(json);
}
/// <summary>
/// Parse JSON string thành ConfigFile (format mới với metadata)
/// </summary>
public static ConfigFile ParseConfigFile(string json)
{
ArgumentException.ThrowIfNullOrWhiteSpace(json, nameof(json));
using var jsonDoc = JsonDocument.Parse(json);
var root = jsonDoc.RootElement;
if (root.ValueKind != JsonValueKind.Object)
{
throw new ArgumentException("JSON must be an object with metadata and variables");
}
// Parse metadata
var id = root.TryGetProperty("id", out var idProp) && idProp.ValueKind == JsonValueKind.String
? Guid.Parse(idProp.GetString() ?? throw new ArgumentException("Invalid id format"))
: throw new ArgumentException("id is required");
var configType = root.GetProperty("configType").GetString()
?? throw new ArgumentException("configType is required");
var createdAt = root.TryGetProperty("createdAt", out var createdAtProp) && createdAtProp.ValueKind == JsonValueKind.String
? DateTime.Parse(createdAtProp.GetString() ?? throw new ArgumentException("Invalid createdAt format"))
: DateTime.UtcNow;
var updatedAt = root.TryGetProperty("updatedAt", out var updatedAtProp) && updatedAtProp.ValueKind == JsonValueKind.String
? DateTime.Parse(updatedAtProp.GetString() ?? throw new ArgumentException("Invalid updatedAt format"))
: DateTime.UtcNow;
var description = root.TryGetProperty("description", out var descProp) && descProp.ValueKind == JsonValueKind.String
? descProp.GetString()
: null;
// Parse variables
if (!root.TryGetProperty("variables", out var variablesProp) || variablesProp.ValueKind != JsonValueKind.Array)
{
throw new ArgumentException("variables array is required");
}
var variables = ParseVariablesArray(variablesProp);
return new ConfigFile
{
Id = id,
ConfigType = configType,
Variables = variables,
CreatedAt = createdAt,
UpdatedAt = updatedAt,
Description = description,
FilePath = $"configs/{configType}.config.json"
};
}
/// <summary>
/// Parse variables array từ JSON element
/// </summary>
private static List<ConfigVariable> ParseVariablesArray(JsonElement variablesElement)
{
var variables = new List<ConfigVariable>();
foreach (var element in variablesElement.EnumerateArray())
{
var variable = new ConfigVariable
{
Name = element.GetProperty("name").GetString() ?? throw new ArgumentException("Variable name is required"),
Type = VariableTypeConverter.ParseType(element.GetProperty("type").GetString() ?? throw new ArgumentException("Variable type is required")),
Value = ParseValue(element),
Min = element.TryGetProperty("min", out var minProp) && minProp.ValueKind != JsonValueKind.Null
? minProp.GetDouble()
: null,
Max = element.TryGetProperty("max", out var maxProp) && maxProp.ValueKind != JsonValueKind.Null
? maxProp.GetDouble()
: null,
Roles = element.TryGetProperty("roles", out var rolesProp)
? rolesProp.GetString() ?? string.Empty
: string.Empty,
EnumValues = element.TryGetProperty("enumValues", out var enumProp) && enumProp.ValueKind == JsonValueKind.Array
? [.. enumProp.EnumerateArray().Select(e => e.GetString() ?? string.Empty)]
: null
};
variables.Add(variable);
}
return variables;
}
/// <summary>
/// Parse JSON stream thành list of ConfigVariable (backward compatibility cho import từ format cũ)
/// Format cũ: [{"name": "port", "type": "int", "value": 8080, "Min": 0, "Max": 65535, "Roles": ""}, ...]
/// </summary>
public static List<ConfigVariable> ParseVariables(Stream jsonStream)
{
using var reader = new StreamReader(jsonStream);
var json = reader.ReadToEnd();
return ParseVariables(json);
}
/// <summary>
/// Parse JSON string thành list of ConfigVariable (backward compatibility cho import từ format cũ)
/// </summary>
public static List<ConfigVariable> ParseVariables(string json)
{
using var jsonDoc = JsonDocument.Parse(json);
var root = jsonDoc.RootElement;
// Check if it's new format (object) or old format (array)
if (root.ValueKind == JsonValueKind.Object)
{
// New format - extract variables
if (root.TryGetProperty("variables", out var variablesProp) && variablesProp.ValueKind == JsonValueKind.Array)
{
return ParseVariablesArray(variablesProp);
}
throw new ArgumentException("JSON object must contain 'variables' array");
}
if (root.ValueKind != JsonValueKind.Array)
{
throw new ArgumentException("JSON must be an array of variables (old format) or object with metadata and variables (new format)");
}
// Old format - array of variables
return ParseVariablesArray(root);
}
/// <summary>
/// Parse value từ JSON element theo type
/// </summary>
private static object? ParseValue(JsonElement element)
{
if (!element.TryGetProperty("value", out var valueProp))
{
throw new ArgumentException("Variable value is required");
}
var typeStr = element.GetProperty("type").GetString()?.ToLower();
return typeStr switch
{
"string" => valueProp.GetString(),
"int" => valueProp.GetInt32(),
"double" => valueProp.GetDouble(),
"bool" => valueProp.GetBoolean(),
"object" => ParseJsonObject(valueProp),
"array" => ParseJsonArray(valueProp),
"enum" => valueProp.GetString(), // Enum values are strings
_ => throw new ArgumentException($"Unsupported type: {typeStr}")
};
}
/// <summary>
/// Parse JSON object thành Dictionary<string, object>
/// </summary>
private static Dictionary<string, object> ParseJsonObject(JsonElement element)
{
if (element.ValueKind != JsonValueKind.Object)
{
throw new ArgumentException("Value must be a JSON object");
}
return JsonSerializer.Deserialize<Dictionary<string, object>>( element.GetRawText()) ?? [];
}
/// <summary>
/// Parse JSON array thành List<object>
/// </summary>
private static List<object> ParseJsonArray(JsonElement element)
{
if (element.ValueKind != JsonValueKind.Array)
{
throw new ArgumentException("Value must be a JSON array");
}
var result = new List<object>();
foreach (var item in element.EnumerateArray())
{
result.Add(item.GetRawText());
}
return result;
}
/// <summary>
/// Serialize ConfigFile thành JSON string (format mới với metadata và variables)
/// </summary>
public static string SerializeConfigFile(ConfigFile config)
{
var jsonObject = new
{
id = config.Id,
configType = config.ConfigType,
createdAt = config.CreatedAt.ToString("O"), // ISO 8601 format
updatedAt = config.UpdatedAt.ToString("O"), // ISO 8601 format
description = config.Description,
variables = config.Variables.Select(v => new
{
name = v.Name,
type = v.Type.ToString().ToLower(),
value = SerializeValue(v.Value, v.Type),
min = v.Min,
max = v.Max,
roles = v.Roles ?? string.Empty,
enumValues = v.EnumValues
}).ToArray()
};
return JsonSerializer.Serialize(jsonObject, JsonOptions);
}
/// <summary>
/// Serialize list of ConfigVariable thành JSON string (chỉ variables, dùng cho export backward compatibility)
/// </summary>
public static string SerializeVariables(List<ConfigVariable> variables)
{
var jsonArray = variables.Select(v => new
{
name = v.Name,
type = v.Type.ToString().ToLower(),
value = SerializeValue(v.Value, v.Type),
min = v.Min,
max = v.Max,
roles = v.Roles ?? string.Empty,
enumValues = v.EnumValues
}).ToArray();
return JsonSerializer.Serialize(jsonArray, JsonOptions);
}
/// <summary>
/// Serialize value theo type (đặc biệt cho Object và Array)
/// </summary>
private static object SerializeValue(object? value, ConfigVariableType type)
{
if (value == null) return null!;
return type switch
{
ConfigVariableType.Object => value is Dictionary<string, object> dict
? dict
: System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, object>>(value.ToString() ?? "{}", JsonOptions) ?? [],
ConfigVariableType.Array => value is List<object> list
? list
: System.Text.Json.JsonSerializer.Deserialize<List<object>>(value.ToString() ?? "[]", JsonOptions) ?? [],
_ => value
};
}
}

View File

@@ -0,0 +1,180 @@
using RobotNet10.CustomConfiguration.Models;
using System.Globalization;
namespace RobotNet10.CustomConfiguration.Helpers;
/// <summary>
/// Helper class cho convert giữa variable type và value
/// </summary>
public static class VariableTypeConverter
{
/// <summary>
/// Convert string type name thành ConfigVariableType enum
/// </summary>
public static ConfigVariableType ParseType(string typeName)
{
ArgumentException.ThrowIfNullOrWhiteSpace(typeName, nameof(typeName));
return typeName.ToLower() switch
{
"string" => ConfigVariableType.String,
"int" => ConfigVariableType.Int,
"double" => ConfigVariableType.Double,
"bool" => ConfigVariableType.Bool,
"object" => ConfigVariableType.Object,
"array" => ConfigVariableType.Array,
"enum" => ConfigVariableType.Enum,
_ => throw new ArgumentException($"Invalid variable type: {typeName}")
};
}
/// <summary>
/// Convert value sang đúng type
/// </summary>
public static object ConvertValue(ConfigVariableType type, object? value)
{
if (value == null)
throw new ArgumentNullException(nameof(value), "Value cannot be null");
return type switch
{
ConfigVariableType.String => value.ToString() ?? string.Empty,
ConfigVariableType.Int => Convert.ToInt32(value, CultureInfo.InvariantCulture),
ConfigVariableType.Double => Convert.ToDouble(value, CultureInfo.InvariantCulture),
ConfigVariableType.Bool => Convert.ToBoolean(value, CultureInfo.InvariantCulture),
ConfigVariableType.Object => ConvertToObject(value),
ConfigVariableType.Array => ConvertToArray(value),
ConfigVariableType.Enum => value.ToString() ?? string.Empty, // Enum values are strings
_ => throw new ArgumentException($"Unsupported type: {type}")
};
}
/// <summary>
/// Convert value thành Dictionary<string, object> (Object type)
/// </summary>
private static Dictionary<string, object> ConvertToObject(object value)
{
if (value is Dictionary<string, object> dict)
return dict;
if (value is System.Text.Json.JsonElement jsonElement && jsonElement.ValueKind == System.Text.Json.JsonValueKind.Object)
{
var result = new Dictionary<string, object>();
foreach (var prop in jsonElement.EnumerateObject())
{
result[prop.Name] = prop.Value.GetRawText();
}
return result;
}
// Try parse as JSON string
var jsonString = value.ToString();
if (!string.IsNullOrEmpty(jsonString))
{
using var doc = System.Text.Json.JsonDocument.Parse(jsonString);
if (doc.RootElement.ValueKind == System.Text.Json.JsonValueKind.Object)
{
var result = new Dictionary<string, object>();
foreach (var prop in doc.RootElement.EnumerateObject())
{
result[prop.Name] = prop.Value.GetRawText();
}
return result;
}
}
throw new ArgumentException("Value cannot be converted to Object type");
}
/// <summary>
/// Convert value thành List<object> (Array type)
/// </summary>
private static List<object> ConvertToArray(object value)
{
if (value is List<object> list)
return list;
if (value is System.Text.Json.JsonElement jsonElement && jsonElement.ValueKind == System.Text.Json.JsonValueKind.Array)
{
var result = new List<object>();
foreach (var item in jsonElement.EnumerateArray())
{
result.Add(item.GetRawText());
}
return result;
}
// Try parse as JSON string
var jsonString = value.ToString();
if (!string.IsNullOrEmpty(jsonString))
{
using var doc = System.Text.Json.JsonDocument.Parse(jsonString);
if (doc.RootElement.ValueKind == System.Text.Json.JsonValueKind.Array)
{
var result = new List<object>();
foreach (var item in doc.RootElement.EnumerateArray())
{
result.Add(item.GetRawText());
}
return result;
}
}
throw new ArgumentException("Value cannot be converted to Array type");
}
/// <summary>
/// Validate value có đúng type không
/// </summary>
public static bool IsValidValue(ConfigVariableType type, object? value)
{
if (value == null) return false;
return type switch
{
ConfigVariableType.String => value is string,
ConfigVariableType.Int => value is int || int.TryParse(value.ToString(), NumberStyles.Integer, CultureInfo.InvariantCulture, out _),
ConfigVariableType.Double => value is double || double.TryParse(value.ToString(), NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out _),
ConfigVariableType.Bool => value is bool || bool.TryParse(value.ToString(), out _),
ConfigVariableType.Object => value is Dictionary<string, object> ||
(value is System.Text.Json.JsonElement je && je.ValueKind == System.Text.Json.JsonValueKind.Object) ||
TryParseJsonObject(value),
ConfigVariableType.Array => value is List<object> ||
(value is System.Text.Json.JsonElement je && je.ValueKind == System.Text.Json.JsonValueKind.Array) ||
TryParseJsonArray(value),
ConfigVariableType.Enum => value is string, // Enum values are always strings
_ => false
};
}
private static bool TryParseJsonObject(object value)
{
try
{
var jsonString = value.ToString();
if (string.IsNullOrEmpty(jsonString)) return false;
using var doc = System.Text.Json.JsonDocument.Parse(jsonString);
return doc.RootElement.ValueKind == System.Text.Json.JsonValueKind.Object;
}
catch (System.Text.Json.JsonException)
{
return false;
}
}
private static bool TryParseJsonArray(object value)
{
try
{
var jsonString = value.ToString();
if (string.IsNullOrEmpty(jsonString)) return false;
using var doc = System.Text.Json.JsonDocument.Parse(jsonString);
return doc.RootElement.ValueKind == System.Text.Json.JsonValueKind.Array;
}
catch (System.Text.Json.JsonException)
{
return false;
}
}
}