// Copyright Epic Games, Inc. All Rights Reserved. using Grpc.Core; using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Text; using System.Threading.Tasks; namespace HordeServer.Utilities { /// /// Exception class designed to allow logging structured log messages /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1032:Implement standard exception constructors", Justification = "")] public class StructuredRpcException : RpcException { /// /// The format string with named parameters /// public string Format { get; } /// /// The argument list /// public object[] Args { get; } /// /// Constructor /// /// Status code to return /// The format string /// Arguments for the format string public StructuredRpcException(StatusCode StatusCode, string Format, params object[] Args) : base(new Status(StatusCode, FormatMessage(Format, Args))) { this.Format = Format; this.Args = Args; } /// /// Replace named arguments in the format message with their values /// /// /// /// static string FormatMessage(string Format, params object[] Args) { string NewFormat = ConvertToFormatString(Format); return String.Format(CultureInfo.CurrentCulture, NewFormat, Args); } /// /// Converts a named parameter format string to a String.Format style string /// /// /// static string ConvertToFormatString(string Format) { int ArgIdx = 0; StringBuilder NewFormat = new StringBuilder(); for (int Idx = 0; Idx < Format.Length; Idx++) { char Character = Format[Idx]; NewFormat.Append(Character); if (Character == '{' && Idx + 1 < Format.Length) { char NextCharacter = Format[Idx + 1]; if ((NextCharacter >= 'a' && NextCharacter <= 'z') || (NextCharacter >= 'A' && NextCharacter <= 'Z') || NextCharacter == '_') { for (int EndIdx = Idx + 2; EndIdx < Format.Length; EndIdx++) { if (Format[EndIdx] == ':' || Format[EndIdx] == '}') { NewFormat.Append(ArgIdx++); Idx = EndIdx - 1; break; } } } } } return NewFormat.ToString(); } } }