AyCode.Core/AyCode.Services/SignalRs/IAcSignalRHubClient.cs

194 lines
6.1 KiB
C#

using AyCode.Core.Extensions;
using AyCode.Core.Interfaces;
using AyCode.Core.Serializers;
using JsonIgnoreAttribute = Newtonsoft.Json.JsonIgnoreAttribute;
using STJIgnore = System.Text.Json.Serialization.JsonIgnoreAttribute;
namespace AyCode.Services.SignalRs;
/// <summary>
/// Message container for serialized parameter IDs.
/// Optimized for common primitive types to avoid full JSON overhead.
/// </summary>
[Obsolete("Use direct object[] binary serialization instead of IdMessage JSON wrapper.")]
public class IdMessage
{
public List<string> Ids { get; private set; }
public IdMessage()
{
Ids = [];
}
/// <summary>
/// Creates IdMessage with multiple parameters serialized directly as JSON.
/// </summary>
public IdMessage(object[] ids)
{
Ids = new List<string>(ids.Length);
for (var i = 0; i < ids.Length; i++)
{
Ids.Add(SignalRSerializationHelper.SerializePrimitiveToJson(ids[i]));
}
}
/// <summary>
/// Creates IdMessage with a single parameter serialized as JSON.
/// </summary>
public IdMessage(object id)
{
Ids = [SignalRSerializationHelper.SerializePrimitiveToJson(id)];
}
/// <summary>
/// Creates IdMessage with multiple Guid parameters.
/// </summary>
public IdMessage(IEnumerable<Guid> ids)
{
var idsArray = ids as Guid[] ?? ids.ToArray();
Ids = new List<string>(idsArray.Length);
for (var i = 0; i < idsArray.Length; i++)
{
Ids.Add(SignalRSerializationHelper.SerializeGuidToJson(idsArray[i]));
}
}
public override string ToString() => string.Join("; ", Ids);
}
/// <summary>
/// Message containing JSON-serialized post data.
/// </summary>
[Obsolete("Use direct object[] binary serialization instead of JSON-in-Binary wrapper.")]
public class SignalPostJsonMessage
{
public string PostDataJson { get; set; } = "";
public SignalPostJsonMessage() { }
protected SignalPostJsonMessage(string postDataJson) => PostDataJson = postDataJson;
}
/// <summary>
/// Generic message containing JSON-serialized post data with typed access.
/// </summary>
[Obsolete("Use direct object[] binary serialization instead of JSON-in-Binary wrapper.")]
public class SignalPostJsonDataMessage<TPostDataType> : SignalPostJsonMessage, ISignalPostMessage<TPostDataType>
{
[JsonIgnore]
[STJIgnore]
private TPostDataType? _postData;
[JsonIgnore]
[STJIgnore]
public TPostDataType PostData
{
get => _postData ??= PostDataJson.JsonTo<TPostDataType>()!;
private init
{
_postData = value;
PostDataJson = _postData.ToJson();
}
}
public SignalPostJsonDataMessage() : base() { }
public SignalPostJsonDataMessage(TPostDataType postData) => PostData = postData;
public SignalPostJsonDataMessage(string postDataJson) : base(postDataJson) { }
}
/// <summary>
/// Simple message containing post data.
/// </summary>
[Obsolete("Use direct object[] binary serialization instead of message wrappers.")]
public class SignalPostMessage<TPostData>(TPostData postData) : ISignalPostMessage<TPostData>
{
public TPostData? PostData { get; set; } = postData;
}
[Obsolete("Use direct object[] binary serialization instead of message wrappers.")]
public interface ISignalPostMessage<TPostData> : ISignalRMessage
{
TPostData? PostData { get; }
}
/// <summary>
/// Message for requesting by Guid ID.
/// </summary>
public class SignalRequestByIdMessage(Guid id) : ISignalRequestMessage<Guid>, IId<Guid>
{
public Guid Id { get; set; } = id;
}
public interface ISignalRequestMessage<TRequestId> : ISignalRMessage
{
TRequestId Id { get; set; }
}
public interface ISignalRMessage { }
public interface ISignalResponseMessage : ISignalRMessage
{
int MessageTag { get; set; }
SignalResponseStatus Status { get; set; }
}
public enum SignalResponseStatus : byte
{
Error = 0,
Success = 5
}
/// <summary>
/// Unified signal response message that supports both JSON and Binary serialization.
/// JSON mode uses GZip compression for reduced payload size.
/// Optimized: uses pooled buffers for decompression, zero-copy deserialization path.
/// </summary>
/// <summary>
/// Lightweight response container for client request-response pipeline and stream wire format.
/// Main send path does NOT use this — server sends (signalParams + object) directly.
/// Used by: (1) client OnReceiveMessage → stores in requestModel, (2) stream path (serialized as blob).
/// </summary>
public sealed class SignalResponseDataMessage : ISignalResponseMessage
{
public int MessageTag { get; set; }
public SignalResponseStatus Status { get; set; }
public AcSerializerType DataSerializerType { get; set; }
/// <summary>
/// Raw response object — on client: protocol-deserialized typed object or byte[].
/// On server (stream path only): raw object for blob serialization.
/// </summary>
[JsonIgnore] [STJIgnore]
public object? RawResponseData { get; set; }
public SignalResponseDataMessage() { }
public SignalResponseDataMessage(int messageTag, SignalResponseStatus status)
{
MessageTag = messageTag;
Status = status;
}
/// <summary>Stream path constructor: stores raw object for blob serialization.</summary>
public SignalResponseDataMessage(int messageTag, SignalResponseStatus status, object? responseData, AcSerializerOptions serializerOptions)
: this(messageTag, status)
{
DataSerializerType = serializerOptions.SerializerType;
RawResponseData = responseData;
}
/// <summary>
/// Extracts response data as T.
/// Protocol eagerly deserializes via SignalDataType → RawResponseData is typed object → direct cast.
/// Consumer's responsibility to handle byte[] if T is byte[].
/// </summary>
public T? GetResponseData<T>()
{
if (RawResponseData is T typed) return typed;
return default;
}
}
public interface IAcSignalRHubClient : IAcSignalRHubBase
{
Task SendMessageToServerAsync(int messageTag, object[]? parameters, int? requestId);
}