FixAntenna/NetCore/FixEngine/Session/Util/ConfigurationAdapter.cs (273 lines of code) (raw):

// Copyright (c) 2021 EPAM Systems // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Security.Authentication; using Epam.FixAntenna.NetCore.Common; using Epam.FixAntenna.NetCore.Common.Logging; using Epam.FixAntenna.NetCore.Common.Utils; using Epam.FixAntenna.NetCore.Configuration; using Epam.FixAntenna.NetCore.FixEngine.Storage; using Epam.FixAntenna.NetCore.Helpers; using Epam.FixAntenna.NetCore.Message; using static Epam.FixAntenna.NetCore.Configuration.Config; namespace Epam.FixAntenna.NetCore.FixEngine.Session.Util { internal sealed class ConfigurationAdapter { private const string DefaultOutTemplate = "{0}.out"; private const string DefaultBackupOutTemplate = "{0}-{3}.out"; private const string DefaultInTemplate = "{0}.inc"; private const string DefaultBackupInTemplate = "{0}-{3}.inc"; private const string DefaultPropertyTemplate = "{0}.properties"; private const string DefaultStateTemplate = "{0}.state"; private const string DefaultQueueTemplate = "{0}.outq"; private const string DefaultDir = "."; private const string StorageBackupDefaultDir = "backup"; private static readonly ILog Log = LogFactory.GetLog(typeof(ConfigurationAdapter)); private static readonly TimeSpan DefaultTimezone = DateTimeHelper.UtcOffset; public Config Configuration { get; } public ConfigurationAdapter(Config configuration) { Configuration = configuration; } public bool IsEnableMessageRejecting => Configuration.GetPropertyAsBoolean(Config.EnableMessageRejecting, false); public int MaxMessagesToSendInBatch => Configuration.GetPropertyAsInt(Config.MaxMessagesToSendInBatch, 1, int.MaxValue, true); public int ThresholdSize => Configuration.GetPropertyAsInt(Config.QueueThresholdSize, 0, int.MaxValue, true); public int ForceLogoff => Configuration.GetPropertyAsInt(Config.ForcedLogoffTimeout, 0, int.MaxValue, true); public string StorageFactoryClass => Configuration.GetProperty(Config.StorageFactory, typeof(FilesystemStorageFactory).FullName); public int AutoReconnectAttempts => Configuration.GetPropertyAsInt(Config.AutoreconnectAttempts); public int GetAutoReconnectAttempts(int defaultValue) { return Configuration.GetPropertyAsInt(Config.AutoreconnectAttempts, defaultValue); } public int AutoReconnectDelay => Configuration.GetPropertyAsInt(Config.AutoreconnectDelayInMs, 0, int.MaxValue, true); public bool IsResetOnSwitchToBackupEnabled => Configuration.GetPropertyAsBoolean(Config.ResetOnSwitchToBackup, false); public bool IsResetOnSwitchToPrimaryEnabled => Configuration.GetPropertyAsBoolean(Config.ResetOnSwitchToPrimary, false); public bool IsAutoSwitchToBackupConnectionEnabled => Configuration.GetPropertyAsBoolean(Config.EnableAutoSwitchToBackupConnection, true); public bool IsCyclicSwitchBackupConnectionEnabled => Configuration.GetPropertyAsBoolean(Config.CyclicSwitchBackupConnection, true); public bool IsSslEnabled => Configuration.GetPropertyAsBoolean(Config.RequireSsl, false); public bool IsNagleEnabled => Configuration.GetPropertyAsBoolean(Config.EnableNagle); public bool IsMessageStatisticEnabled => Configuration.GetPropertyAsBoolean(Config.EnableMessageStatistic, true); public long MaxMessageSize => Configuration.GetPropertyAsBytesLength(Config.MaxMessageSize); public string ConnectAddress => Configuration.GetProperty(Config.ConnectAddress); public string TradePeriodBegin => Configuration.GetProperty(Config.TradePeriodBegin); public string TradePeriodEnd => Configuration.GetProperty(Config.TradePeriodEnd); public TimeZoneInfo TradePeriodTimeZone { get { var timeZone = Configuration.GetProperty(Config.TradePeriodTimeZone); if (DateTimeHelper.TryParseTimeZone(timeZone, out var timeZoneInfo)) { return timeZoneInfo; } Log.Warn($"Using UTC time zone instead of '{timeZone}'"); return TimeZoneInfo.Utc; } } public bool IsSendingTimeAccuracyCheckEnabled => Configuration.GetPropertyAsBoolean(Config.CheckSendingTimeAccuracy, false); public int GetReasonableDelay(int defaultValue) { var reasonableDelay = Configuration.GetPropertyAsInt(Config.Delay, defaultValue); if (reasonableDelay < 0) { reasonableDelay = defaultValue; if (Log.IsWarnEnabled) { Log.Warn("Parameter \"" + Config.Delay + "\" must be integer and not negative"); } } return reasonableDelay; } public int GetAccuracy(int defaultValue) { var accuracyInMs = Configuration.GetPropertyAsInt(Config.Accuracy, defaultValue); if (accuracyInMs < 0) { accuracyInMs = defaultValue; if (Log.IsWarnEnabled) { Log.Warn("Parameter \"" + Config.Accuracy + "\" must be integer and not negative"); } } return accuracyInMs; } public TimestampPrecision TimestampsPrecisionInTags => GetTimestampsPrecision(Config.TimestampsPrecisionInTags); public TimestampPrecision TimestampsPrecisionInLogs => GetTimestampsPrecision(Config.TimestampsPrecisionInLogs); public TimestampPrecision BackupTimestampsPrecision => GetTimestampsPrecision(Config.BackupTimestampsPrecision); private TimestampPrecision GetTimestampsPrecision(string precisionPropertyName) { var value = Configuration.GetProperty(precisionPropertyName, "MILLI") .ToUpper(CultureInfo.InvariantCulture); if (!(Enum.TryParse(value, true, out TimestampPrecision timestampsPrecision) && Enum.IsDefined(typeof(TimestampPrecision), timestampsPrecision))) { Log.Warn("Incorrect value in '" + precisionPropertyName + "', value:'" + value + "'." + "Only 'Second', 'Milli', 'Micro' and 'Nano' values are valid. Using default: Milli"); timestampsPrecision = TimestampPrecision.Milli; } return timestampsPrecision; } public int MaxDifference => Configuration.GetPropertyAsInt(Config.ResendRequestNumberOfMessagesLimit, 0, int.MaxValue, true); public bool IsWelformedValidationEnabled => Configuration.GetPropertyAsBoolean(Config.WelformedValidator, false); public bool IsFieldsValidationEnabled => Configuration.GetPropertyAsBoolean(Config.AllowedFieldsValidation, false); public bool IsRequiredFieldsValidationEnabled => Configuration.GetPropertyAsBoolean(Config.RequiredFieldsValidation, false); public bool IsFieldOrderValidationEnabled => Configuration.GetPropertyAsBoolean(Config.FieldOrderValidation, false); public bool IsDuplicateFieldsValidationEnabled => Configuration.GetPropertyAsBoolean(Config.DuplicateFieldsValidation, false); public bool IsFieldTypeValidationEnabled => Configuration.GetPropertyAsBoolean(Config.FieldTypeValidation, false); public bool IsConditionalValidationEnabled => Configuration.GetPropertyAsBoolean(Config.ConditionalValidation, false); public bool IsGroupValidationEnabled => Configuration.GetPropertyAsBoolean(Config.GroupValidation, false); public bool IsValidationEnabled => Configuration.GetPropertyAsBoolean(Config.Validation, false); #region Reset SeqNum sheduled public bool IsResetSeqNumTimeEnabled => Configuration.GetPropertyAsBoolean(Config.PerformResetSeqNumTime, false); public string ResetSequenceTime => Configuration.GetProperty(Config.ResetSequenceTime, "00:00:00"); public string ResetSequenceTimeZone => Configuration.GetProperty(Config.ResetSequenceTimeZone, "UTC"); private TimeSpan ParseResetSequenceTimeZone() { var userTimeZoneId = ResetSequenceTimeZone; if (DateTimeHelper.TryParseTimeZoneOffset(userTimeZoneId, out var offset)) { return offset; } Log.Warn("Incorrect value in" + Config.ResetSequenceTimeZone + "', value:'" + userTimeZoneId + "'. Using default: UTC"); offset = DefaultTimezone; return offset; } public long ResetSequenceTimeInUserTimestamp { get { var timeZone = ParseResetSequenceTimeZone(); var resetSeqNumTime = ResetSequenceTime; DateTimeBuilder builder; try { var time = FixTypes.ParseShortTime(resetSeqNumTime.AsByteArray()); builder = new DateTimeBuilder(DateTime.UtcNow.Date).SetHour(time.Hour).SetMinute(time.Minute) .SetSecond(time.Second); } catch (Exception) { Log.Warn("Incorrect value in '" + Config.ResetSequenceTime + "', value:'" + resetSeqNumTime + "'. Using default: 00:00:00"); builder = new DateTimeBuilder(DateTime.UtcNow.Date).SetHour(0).SetMinute(0).SetSecond(0); } builder = builder.SetMillisecond(0); return builder.Build(timeZone).TotalMilliseconds(); } } #endregion public StorageCleanupMode StorageCleanupMode { get { var propertyValue = Configuration.GetProperty(Config.StorageCleanupMode, StorageCleanupMode.Backup.ToString()); if (!(Enum.TryParse(propertyValue, true, out StorageCleanupMode cleanupMode) && Enum.IsDefined(typeof(StorageCleanupMode), cleanupMode))) { Log.Warn("Incorrect value in '" + Config.StorageCleanupMode + "', value:'" + propertyValue + "'. Using default: Backup"); cleanupMode = StorageCleanupMode.Backup; } return cleanupMode; } } public string StorageDirectory => Configuration.GetProperty(Config.StorageDirectory, DefaultDir); public string BackupStorageDirectory => Configuration.GetProperty(Config.StorageBackupDir, StorageBackupDefaultDir); public string OutgoingStorageTemplate => Configuration.GetProperty(Config.OutgoingLogFile, DefaultOutTemplate); public string BackupOutgoingStorageTemplate => Configuration.GetProperty(Config.BackupOutgoingLogFile, DefaultBackupOutTemplate); public string IncomingStorageTemplate => Configuration.GetProperty(Config.IncomingLogFile, DefaultInTemplate); public string BackupIncomingStorageTemplate => Configuration.GetProperty(Config.BackupIncomingLogFile, DefaultBackupInTemplate); public string PropertiesTemplate => Configuration.GetProperty(Config.SessionInfoFile, DefaultPropertyTemplate); //FIXME_NOW public string StateTemplate => Configuration.GetProperty("sessionStateFile", DefaultStateTemplate); public string OutgoingQueueTemplate => Configuration.GetProperty(Config.OutgoingQueueFile, DefaultQueueTemplate); public bool IsIncomingStorageIndexed => Configuration.GetPropertyAsBoolean(Config.IncomingStorageIndexed, false); public bool IsOutgoingStorageIndexed => Configuration.GetPropertyAsBoolean(Config.OutgoingStorageIndexed, true); public bool IsInMemoryQueueEnabled => Configuration.GetPropertyAsBoolean(Config.InMemoryQueue); public bool IsMemoryMappedQueueEnabled => Configuration.GetPropertyAsBoolean(Config.MemoryMappedQueue, true); public bool IsIntraDeySeqNumResetEnabled => Configuration.GetPropertyAsBoolean(Config.IntraDaySeqnumReset, false); public int HbtReasonableTransmissionTime => Configuration.GetPropertyAsInt(Config.HbtReasonableTransmissionTime, 0, int.MaxValue, true); public bool IsOrigSendingTimeCheckingEnabled => Configuration.GetPropertyAsBoolean(Config.OrigSendingTimeChecking, true); public bool IsIgnorePossDupForGapFill => Configuration.GetPropertyAsBoolean(Config.IgnorePossDupForGapFill, true); public bool IsQuietLogonModeEnabled => Configuration.GetPropertyAsBoolean(Config.QuietLogonMode, false); public int TestRequestsNumberUponDisconnection => Configuration.GetPropertyAsInt(Config.TestRequestsNumberUponDisconnection, 1); public bool AdvancedResendRequestProcessing => Configuration.GetPropertyAsBoolean(Config.AdvancedResendRequestProcessing, false); public bool SkipDuplicatedResendRequests => Configuration.GetPropertyAsBoolean(Config.SkipDuplicatedResendRequest, false); public bool PossDupSmartDelivery => Configuration.GetPropertyAsBoolean(Config.PossDupSmartDelivery, false); public long LogonWaitTimeout => Configuration.GetPropertyAsInt(Config.LoginWaitTimeout, 0, int.MaxValue, true); public bool ValidateCheckSum => Configuration.GetPropertyAsBoolean(Config.ValidateCheckSum, true); public int LogoutWaitTimeout => Configuration.GetPropertyAsInt(Config.LogoutWaitTimeout); public string ServerAcceptorStrategy => Configuration.GetProperty(Config.ServerAcceptorStrategy, "Epam.FixAntenna.NetCore.FixEngine.Acceptor.AllowNonRegisteredAcceptorStrategyHandler"); public bool SwitchOffSendingMultipleResendRequests => Configuration.GetPropertyAsBoolean(Config.SwitchOffSendingMultipleResendRequests, false); public SendingMode PreferredSendingMode { get { var sendingMode = Configuration.GetProperty(Config.PreferredSendingMode, SendingMode.Sync.ToString()); if (!(Enum.TryParse(sendingMode.ToUpper(CultureInfo.InvariantCulture), true, out SendingMode mode) && Enum.IsDefined(typeof(SendingMode), mode))) { mode = SendingMode.Sync; if (Log.IsWarnEnabled) { Log.Warn("Invalid value for property \"" + Config.PreferredSendingMode + "\". Will be used sync mode by default"); } } return mode; } } public int GetWaitForQueuingMessages(int defaultVal) => Configuration.GetPropertyAsInt(Config.WaitForMsgQueuingDelay, defaultVal); public bool IgnoreSeqNumTooLowAtLogon => Configuration.GetPropertyAsBoolean(Config.IgnoreSeqNumTooLowAtLogon); public int AllowedCountOfSimilarRr => Configuration.GetPropertyAsInt(Config.AllowedCountOfSimilarRr); public bool HandleSeqNumAtLogon => Configuration.GetPropertyAsBoolean(Config.HandleSeqnumAtLogon); public int TcpSendBufferSize => Configuration.GetPropertyAsInt(Config.TcpSendBufferSize, 0); public int TcpReceiveBufferSize => Configuration.GetPropertyAsInt(Config.TcpReceiveBufferSize, 0); public bool ValidateGarbledMessage => Configuration.GetPropertyAsBoolean(Config.ValidateGarbledMessage, true); public bool MarkInMessageTime => Configuration.GetPropertyAsBoolean(Config.MarkIncomingMessageTime, false); public string SslCertificate => Configuration.GetProperty(Config.SslCertificate); public string SslCertificatePassword => Configuration.GetProperty(Config.SslCertificatePassword); public string RawTags => Configuration.GetProperty(Config.RawTags); public SslProtocols SslProtocol { get { var ssl = Configuration.GetProperty(Config.SslProtocol); if (Enum.TryParse<SslProtocols>(ssl, out var value) && Enum.IsDefined(typeof(SslProtocols), value)) { return value; } throw new ArgumentException("Property sslProtocol have wrong value:" + ssl); } } public bool SslCheckCertificateRevocation => Configuration.GetPropertyAsBoolean(Config.SslCheckCertificateRevocation); public string SslServerName => Configuration.GetProperty(Config.SslServerName); public string SslCaCertificate => Configuration.GetProperty(Config.SslCaCertificate); public bool SslValidatePeerCertificate => Configuration.GetPropertyAsBoolean(Config.SslValidatePeerCertificate); public List<int> SslPorts => ParsePorts(Configuration.GetProperty(Config.SslPort, new ValidatorIntegerList(1,65535), nullable: true, warnInLog: true)).ToList(); public List<int> Ports => ParsePorts(Configuration.GetProperty(Config.Port, new ValidatorIntegerList(1, 65535), nullable: true, warnInLog: true)).ToList(); public bool IsSslPort(int port) => SslPorts.Contains(port); private static IEnumerable<int> ParsePorts(string rawPorts) => (rawPorts ?? string.Empty) .Split(new[] { ',', ';', ' ' }, StringSplitOptions.RemoveEmptyEntries) .Select(p => int.TryParse(p.Trim(), out var port) ? port : -1) .Where(port => port > -1); public ResetSeqNumFromFirstLogonMode ResetSeqNumFromFirstLogonMode() { var resetSeqNumFromFirstLogon = Configuration.GetProperty(ResetSeqNumFromFirstLogon); if (TryParseEnum<ResetSeqNumFromFirstLogonMode>(resetSeqNumFromFirstLogon, out var value) ) { return value; } throw new ArgumentException($"Property {ResetSeqNumFromFirstLogon} has wrong value:" + resetSeqNumFromFirstLogon); } private bool TryParseEnum<T>(string value, out T result) where T : struct { return Enum.TryParse(value, true, out result) && Enum.IsDefined(typeof(T), result); } } }