using System.Diagnostics; using TakeoutSaaS.Shared.Abstractions.Diagnostics; namespace TakeoutSaaS.Shared.Abstractions.Results; /// /// 统一的 API 返回结果包装。 /// /// 数据载荷类型。 public sealed record ApiResponse { /// /// 是否成功。 /// public bool Success { get; init; } /// /// 状态/错误码(默认 200)。 /// public int Code { get; init; } = 200; /// /// 提示信息。 /// public string? Message { get; init; } /// /// 业务数据。 /// public T? Data { get; init; } /// /// 错误详情(如字段验证错误)。 /// public object? Errors { get; init; } /// /// TraceId,便于链路追踪。 /// public string TraceId { get; init; } = string.Empty; /// /// 时间戳(UTC)。 /// public DateTime Timestamp { get; init; } = DateTime.UtcNow; /// /// 成功返回。 /// /// 业务数据。 /// 提示信息。 /// 封装后的成功响应。 public static ApiResponse Ok(T data, string? message = "操作成功") => Create(true, 200, message, data); /// /// 无数据的成功返回。 /// /// 提示信息。 /// 封装后的成功响应。 public static ApiResponse Ok(string? message = "操作成功") => Create(true, 200, message, default); /// /// 兼容旧名称:成功结果。 /// /// 业务数据。 /// 提示信息。 /// 封装后的成功响应。 public static ApiResponse SuccessResult(T data, string? message = "操作成功") => Ok(data, message); /// /// 错误返回。 /// /// 错误码。 /// 错误提示。 /// 错误详情。 /// 封装后的失败响应。 public static ApiResponse Error(int code, string message, object? errors = null) => Create(false, code, message, default, errors); /// /// 兼容旧名称:失败结果。 /// /// 错误码。 /// 错误提示。 /// 封装后的失败响应。 public static ApiResponse Failure(int code, string message) => Error(code, message); /// /// 附加错误详情。 /// /// 错误详情。 /// 包含错误详情的新响应。 public ApiResponse WithErrors(object? errors) => this with { Errors = errors }; private static ApiResponse Create(bool success, int code, string? message, T? data, object? errors = null) => new() { Success = success, Code = code, Message = message, Data = data, Errors = errors, TraceId = ResolveTraceId(), Timestamp = DateTime.UtcNow }; /// /// 解析当前 TraceId。 /// /// 当前有效的 TraceId。 private static string ResolveTraceId() { if (!string.IsNullOrWhiteSpace(TraceContext.TraceId)) { return TraceContext.TraceId; } if (!string.IsNullOrWhiteSpace(TraceContext.TraceId)) { return TraceContext.TraceId; } if (Activity.Current?.Id is { } id && !string.IsNullOrWhiteSpace(id)) { return id; } return IdFallbackGenerator.Instance.NextId().ToString(); } } /// /// 作为 TraceId 缺失时的本地雪花 ID 备用生成器。 /// internal sealed class IdFallbackGenerator { /// /// 延迟初始化的单例实例承载。 /// private static readonly Lazy Lazy = new(() => new IdFallbackGenerator()); /// /// 获取备用雪花生成器单例。 /// public static IdFallbackGenerator Instance => Lazy.Value; private readonly object _sync = new(); private long _lastTimestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); private long _sequence; private IdFallbackGenerator() { } /// /// 生成雪花风格的本地备用 ID。 /// /// 本地生成的雪花 ID。 public long NextId() { lock (_sync) { var timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); if (timestamp == _lastTimestamp) { _sequence = (_sequence + 1) & 4095; if (_sequence == 0) { timestamp = WaitNextMillis(_lastTimestamp); } } else { _sequence = 0; } _lastTimestamp = timestamp; return ((timestamp - 1577836800000L) << 22) | _sequence; } } /// /// 等待到下一个毫秒以避免序列冲突。 /// /// 上一毫秒的时间戳。 /// 下一个时间戳(毫秒)。 private static long WaitNextMillis(long lastTimestamp) { var timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); while (timestamp <= lastTimestamp) { Thread.SpinWait(100); timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); } return timestamp; } }