// Copyright © WireMock.Net
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using ProtoBufJsonConverter;
using ProtoBufJsonConverter.Models;
using Stef.Validation;
using WireMock.Models;
namespace WireMock.Util;
///
/// Some helper methods for Proto Definitions.
///
internal static class ProtoDefinitionDataHelper
{
///
/// Builds a dictionary of ProtoDefinitions from a directory.
/// - The key will be the filename without extension.
/// - The value will be the ProtoDefinition with an extra comment with the relative path to each .proto file so it can be used by the WireMockProtoFileResolver.
///
/// The directory to start from.
/// The token to monitor for cancellation requests. The default value is System.Threading.CancellationToken.None.
public static async Task FromDirectory(string directory, CancellationToken cancellationToken = default)
{
Guard.NotNullOrEmpty(directory);
var fileNameMappedToProtoDefinition = new Dictionary();
var filePaths = Directory.EnumerateFiles(directory, "*.proto", SearchOption.AllDirectories);
foreach (var filePath in filePaths)
{
// Get the relative path to the directory (note that this will be OS specific).
var relativePath = FilePathUtils.GetRelativePath(directory, filePath);
// Make it a valid proto import path
var protoRelativePath = relativePath.Replace(Path.DirectorySeparatorChar, '/');
// Build comment and get content from file.
var comment = $"// {protoRelativePath}";
#if NETSTANDARD2_0 || NET462
var content = File.ReadAllText(filePath);
#else
var content = await File.ReadAllTextAsync(filePath, cancellationToken);
#endif
// Only add the comment if it's not already defined.
var modifiedContent = !content.StartsWith(comment) ? $"{comment}\n{content}" : content;
var key = Path.GetFileNameWithoutExtension(filePath);
fileNameMappedToProtoDefinition.Add(key, modifiedContent);
}
var converter = SingletonFactory.GetInstance();
var resolver = new WireMockProtoFileResolver(fileNameMappedToProtoDefinition.Values);
var messageTypeMappedToWithProtoDefinition = new Dictionary();
foreach (var protoDefinition in fileNameMappedToProtoDefinition.Values)
{
var infoRequest = new GetInformationRequest(protoDefinition, resolver);
try
{
var info = await converter.GetInformationAsync(infoRequest, cancellationToken);
foreach (var messageType in info.MessageTypes)
{
messageTypeMappedToWithProtoDefinition[messageType.Key] = protoDefinition;
}
}
catch
{
// Ignore
}
}
return new ProtoDefinitionData(fileNameMappedToProtoDefinition);
}
}