using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Json.LitJson;
namespace ServiceClientGenerator.DefaultConfiguration
{
public interface IDefaultConfigurationParser
{
///
/// Parses the passed to populate a
///
///
DefaultConfigurationModel Parse(string json);
}
public class DefaultConfigurationParser : IDefaultConfigurationParser
{
///
public DefaultConfigurationModel Parse(string json)
{
try
{
var dataModel = JsonMapper.ToObject(json);
return ConvertDataModel(dataModel);
}
catch (Exception e)
{
throw new Exception(
$"Error processing Default Configuration Json: {e.Message} \r\n\r\n" +
$"Json: \r\n{json}", e);
}
}
private DefaultConfigurationModel ConvertDataModel(SdkDefaultConfigurationJsonDataModel dataModel)
{
var modes =
dataModel
.documentation
.Modes
.Select(x => new
{
DocumentationModel = x,
ModeModel = dataModel.Modes.FirstOrDefault(m => m.Name == x.ModeName)
})
.Select(x =>
new DefaultConfigurationMode
{
Name = x.DocumentationModel.ModeName.ToPascalCase(),
Documentation = x.DocumentationModel.Documentation,
RetryMode =
ApplyModifiersEnum(
EnumParse(dataModel.@base.retryMode),
x.ModeModel.ModifiersForConfiguration(nameof(SdkDefaultConfigurationJsonDataModel.BaseConfig.retryMode))),
S3UsEast1RegionalEndpoint =
ApplyModifiersEnum(
EnumParse(dataModel.@base.s3UsEast1RegionalEndpoints),
x.ModeModel.ModifiersForConfiguration(nameof(SdkDefaultConfigurationJsonDataModel.BaseConfig.s3UsEast1RegionalEndpoints))),
StsRegionalEndpoints =
ApplyModifiersEnum(
EnumParse(dataModel.@base.stsRegionalEndpoints),
x.ModeModel.ModifiersForConfiguration(nameof(SdkDefaultConfigurationJsonDataModel.BaseConfig.stsRegionalEndpoints))),
ConnectTimeout =
ApplyModifiersTimeSpan(
dataModel.@base.connectTimeoutInMillis,
x.ModeModel.ModifiersForConfiguration(nameof(SdkDefaultConfigurationJsonDataModel.BaseConfig.connectTimeoutInMillis))),
TlsNegotiationTimeout =
ApplyModifiersTimeSpan(
dataModel.@base.tlsNegotiationTimeoutInMillis,
x.ModeModel.ModifiersForConfiguration(nameof(SdkDefaultConfigurationJsonDataModel.BaseConfig.tlsNegotiationTimeoutInMillis))),
TimeToFirstByteTimeout =
ApplyModifiersTimeSpan(
dataModel.@base.timeToFirstByteTimeoutInMillis,
x.ModeModel.ModifiersForConfiguration(nameof(SdkDefaultConfigurationJsonDataModel.BaseConfig.timeToFirstByteTimeoutInMillis))),
HttpRequestTimeout =
ApplyModifiersTimeSpan(
dataModel.@base.httpRequestTimeoutInMillis,
x.ModeModel.ModifiersForConfiguration(nameof(SdkDefaultConfigurationJsonDataModel.BaseConfig.httpRequestTimeoutInMillis)))
})
.ToList();
return new DefaultConfigurationModel
{
Modes = modes,
ConfigurationOptionDocumentation =
dataModel
.documentation
.Configuration
.ToDictionary(
kvp => kvp.ConfigurationName.ToUpperFirstCharacter(),
kvp => kvp.Documentation)
};
}
private TimeSpan? ApplyModifiersTimeSpan(int? baseTimeInMillis, IEnumerable modifiers)
{
modifiers = modifiers ?? Enumerable.Empty();
TimeSpan? workingValue =
baseTimeInMillis.HasValue
? (TimeSpan?) TimeSpan.FromMilliseconds(baseTimeInMillis.Value)
: null;
foreach (var modifier in modifiers)
{
switch (modifier.Operation)
{
case SdkDefaultConfigurationJsonDataModel.ModifierOperation.add:
workingValue = (workingValue ?? TimeSpan.Zero).Add(TimeSpan.FromMilliseconds(double.Parse(modifier.Value.ToString())));
break;
case SdkDefaultConfigurationJsonDataModel.ModifierOperation.multiply:
workingValue = TimeSpan.FromMilliseconds((workingValue?.TotalMilliseconds ?? 1) * double.Parse(modifier.Value.ToString()));
break;
case SdkDefaultConfigurationJsonDataModel.ModifierOperation.@override:
workingValue = TimeSpan.FromMilliseconds(double.Parse(modifier.Value.ToString()));
break;
default:
throw new ArgumentOutOfRangeException($"Error: Update switch statement to handle case [{modifier.Operation}]");
}
}
return workingValue;
}
private T ApplyModifiersEnum(T baseValue, IEnumerable modifiers)
where T: struct
{
modifiers = modifiers ?? new SdkDefaultConfigurationJsonDataModel.Modifier[0];
var workingValue = baseValue;
foreach (var modifier in modifiers)
{
switch (modifier.Operation)
{
case SdkDefaultConfigurationJsonDataModel.ModifierOperation.@override:
workingValue = EnumParse(modifier.Value?.ToString());
break;
case SdkDefaultConfigurationJsonDataModel.ModifierOperation.add:
case SdkDefaultConfigurationJsonDataModel.ModifierOperation.multiply:
throw new InvalidOperationException($"Can not apply Operation [{modifier.Operation}] to Enum");
default:
throw new ArgumentOutOfRangeException($"Error: Update switch statement to handle case [{modifier.Operation}]");
}
}
return workingValue;
}
private T EnumParse(string s)
where T : struct
{
s = s ?? "";
if (Enum.TryParse(s, ignoreCase: true, out var result))
return result;
throw new Exception(
$"Failed parsing [{s}] as [{typeof(T).Name}]. " +
$"Valid values are [{string.Join(",", Enum.GetNames(typeof(T)))}]");
}
}
}