You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
OMS.NET/Instructs/Instruct.cs

169 lines
7.0 KiB
C#

using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace OMS.NET.Instructs
{
/// <summary>
/// 声明json转换的命名策略
/// </summary>
class InstructNamingPolicy : JsonNamingPolicy
{
public override string ConvertName(string name)
{
return Convert(name);
}
public static string Convert(string name) => name switch
{
"Type" => "type",
"Class" => "class",
"Conveyor" => "conveyor",
"Time" => "time",
"Data" => "data",
_ => name,
};
}
/// <summary>
/// 实现依据type和class的值决定反序列化的对象类型
/// </summary>
class InstructConverter : JsonConverter<Instruct>
{
public override Instruct Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
using JsonDocument doc = JsonDocument.ParseValue(ref reader);
JsonElement root = doc.RootElement;
//Console.WriteLine(root.GetRawText());
if (root.TryGetProperty("type", out JsonElement typeProperty))
{
string? typeValue = typeProperty.GetString();
string? classValue = root.TryGetProperty("class", out JsonElement classProperty) ? classProperty.GetString() : null;
Instruct? instruct = typeValue switch
{
//实现新指令需在这里添加反序列化类型,限定为客户端发过来的指令类型
"get_publickey" => JsonSerializer.Deserialize<GetPublickeyInstruct>(root.GetRawText(), options),
"get_serverImg" => JsonSerializer.Deserialize<GetServerImgInstruct>(root.GetRawText(), options),
"get_serverConfig" => JsonSerializer.Deserialize<GetServerConfigInstruct>(root.GetRawText(), options),
"login" => JsonSerializer.Deserialize<LoginInstruct>(root.GetRawText(), options),
"test" => JsonSerializer.Deserialize<TestInstruct>(root.GetRawText(), options),
"get_userData" => JsonSerializer.Deserialize<GetUserDataInstruct>(root.GetRawText(), options),
"get_presence" => JsonSerializer.Deserialize<GetPresenceInstruct>(root.GetRawText(), options),
"get_mapData" => JsonSerializer.Deserialize<GetMapDataInstruct>(root.GetRawText(), options),
"get_mapLayer" => JsonSerializer.Deserialize<GetMapLayerInstruct>(root.GetRawText(), options),
"ping" => JsonSerializer.Deserialize<PingInstuct>(root.GetRawText(), options),
//广播指令
"broadcast" => classValue switch
{
//广播指令继承结构
"point" => JsonSerializer.Deserialize<AddElementBroadcastInstruct>(root.GetRawText(), options),
"line" => JsonSerializer.Deserialize<AddElementBroadcastInstruct>(root.GetRawText(), options),
"area" => JsonSerializer.Deserialize<AddElementBroadcastInstruct>(root.GetRawText(), options),
"curve" => JsonSerializer.Deserialize<AddElementBroadcastInstruct>(root.GetRawText(), options),
_ => JsonSerializer.Deserialize<Instruct>(root.GetRawText(), options)
},
_ => null
} ?? throw new JsonException($"{typeValue} 反序列化失败");
return instruct;
}
else
{
throw new JsonException("type property not found");
}
}
public override void Write(Utf8JsonWriter writer, Instruct value, JsonSerializerOptions options)
{
//JsonSerializer.Serialize(writer, (object)value, options); 这个在Data是对象时导致了无限递归调用
writer.WriteStartObject();
writer.WriteString(InstructNamingPolicy.Convert(nameof(Instruct.Type)), value.Type);
if (value.Class != null)
{
writer.WriteString(InstructNamingPolicy.Convert(nameof(Instruct.Class)), value.Class);
}
if (value.Conveyor != null)
{
writer.WriteString(InstructNamingPolicy.Convert(nameof(Instruct.Conveyor)), value.Conveyor);
}
if (value.Time != null)
{
writer.WriteString(InstructNamingPolicy.Convert(nameof(Instruct.Time)), value.Time);
}
if (value.Data != null)
{
writer.WritePropertyName(InstructNamingPolicy.Convert(nameof(Instruct.Data)));
JsonSerializer.Serialize(writer, value.Data, value.Data.GetType(), options);
}
writer.WriteEndObject();
}
}
public class Instruct
{
public static readonly JsonSerializerOptions options = new()
{
ReadCommentHandling = JsonCommentHandling.Skip, //允许注释
AllowTrailingCommas = true,//允许尾随逗号
PropertyNamingPolicy = new InstructNamingPolicy(), // 属性名为定制转换
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, // 忽略 null 值
WriteIndented = true, // 美化输出
//PropertyNameCaseInsensitive = true,//属性名忽略大小写
Converters = { new InstructConverter() },
};
public string Type { get; set; }
public string? Class { get; set; }
public string? Conveyor { get; set; }
public string? Time { get; set; }
public dynamic? Data { get; set; }
[JsonIgnore]
public bool IsResponse { get; set; } = false;
[JsonIgnore]
public bool IsBroadcast { get; set; } = false;
[JsonIgnore]
public List<Instruct> ResponseOrBroadcastInstructs { get; set; } = new();
public Instruct()
{
this.Type = "";
}
/// <summary>
/// 指令处理逻辑
/// </summary>
/// <returns>将耗时任务交给Task以不阻塞单个连接的多个请求</returns>
public virtual Task Handler(string wsid)
{
return Task.CompletedTask;
}
public async Task HandlerAndMeasure(string wsid)
{
Stopwatch stopWatch = new();
stopWatch.Start();
await Handler(wsid);
stopWatch.Stop();
GlobalArea.Log.Debug($"处理{this.GetType()}耗时:{stopWatch.ElapsedMilliseconds}ms");
}
public string ToJsonString()
{
return JsonSerializer.Serialize(this, options);
}
public static Instruct? JsonStringParse(string jsonString)
{
try
{
return JsonSerializer.Deserialize<Instruct>(jsonString, options);
}
catch (Exception ex)
{
GlobalArea.Log.Error(ex.Message);
return null;
}
}
}
}