Удалены <remarks>, <summary> сжаты до короткой фразы, вырезаны ссылки на Task/Ruling/этап/python/прототип; //-комментарии со ссылками на процесс удалены; то же в .proto. Правила обновлены в docs/spec/Код-стайл-Дейл.md. Строк комментариев 27210 -> ~19100.
86 lines
3.5 KiB
C#
86 lines
3.5 KiB
C#
using Deal.Grpc.Telegram;
|
||
using Deal.Infrastructure.Integrations.Options;
|
||
using Grpc.Core;
|
||
using Grpc.Net.Client;
|
||
|
||
namespace Deal.Infrastructure.Integrations.Models;
|
||
|
||
/// <summary>
|
||
/// Транспорт gRPC-клиента telegram-service
|
||
/// </summary>
|
||
public sealed class TelegramGrpcConnection : IDisposable
|
||
{
|
||
/// <summary>
|
||
/// Env-ключ ожидаемого service-token.
|
||
/// </summary>
|
||
public const string ServiceTokenEnvKey = "DEAL_SERVICE_TOKEN";
|
||
|
||
/// <summary>
|
||
/// Ключ gRPC-metadata с tenant-id.
|
||
/// </summary>
|
||
public const string TenantIdMetadataKey = "tenant-id";
|
||
|
||
/// <summary>
|
||
/// Ключ gRPC-metadata с service-token.
|
||
/// </summary>
|
||
public const string ServiceTokenMetadataKey = "service-token";
|
||
|
||
private readonly GrpcChannel _channel;
|
||
private readonly string _serviceToken;
|
||
|
||
/// <summary>
|
||
/// Создаёт транспорт telegram-service по конфигурации и env-токену
|
||
/// </summary>
|
||
/// <param name="options">Конфигурация секции <c>Services:Telegram</c> (endpoint).</param>
|
||
/// <param name="mtlsCertificates">Сертификаты mTLS: null — plaintext-канал (dev, флаг выключен).</param>
|
||
/// <exception cref="InvalidOperationException">Пустой endpoint или пустой DEAL_SERVICE_TOKEN.</exception>
|
||
public TelegramGrpcConnection(TelegramServiceOptions options, MtlsCertificates? mtlsCertificates = null)
|
||
{
|
||
ArgumentNullException.ThrowIfNull(options);
|
||
if (string.IsNullOrWhiteSpace(options.Endpoint))
|
||
{
|
||
throw new InvalidOperationException(
|
||
$"TelegramGrpcConnection: не задан endpoint telegram-service (секция \"{TelegramServiceOptions.SectionName}:Endpoint\").");
|
||
}
|
||
|
||
_serviceToken = Environment.GetEnvironmentVariable(ServiceTokenEnvKey) ?? string.Empty;
|
||
if (_serviceToken.Length == 0)
|
||
{
|
||
throw new InvalidOperationException(
|
||
$"TelegramGrpcConnection: не задан env {ServiceTokenEnvKey} — telegram-service отвергнет вызовы (fail-closed, Ruling 1).");
|
||
}
|
||
|
||
GrpcChannelOptions channelOptions = new() { MaxRetryAttempts = 0 };
|
||
if (mtlsCertificates is not null)
|
||
{
|
||
channelOptions.HttpHandler = mtlsCertificates.CreateClientHttpHandler();
|
||
}
|
||
|
||
_channel = GrpcChannel.ForAddress(options.Endpoint, channelOptions);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Создаёт клиент RPC TelegramService поверх общего канала
|
||
/// </summary>
|
||
/// <returns>Клиент сервиса Telegram (команды ядра наружу).</returns>
|
||
public TelegramService.TelegramServiceClient CreateClient() => new(_channel);
|
||
|
||
/// <summary>
|
||
/// Собирает обязательные metadata вызова
|
||
/// </summary>
|
||
/// <param name="tenantId">Id тенанта (строка, формат N — как в сессиях telegram-service).</param>
|
||
/// <returns>Metadata для CallOptions вызова.</returns>
|
||
public Metadata CreateMetadata(string tenantId)
|
||
{
|
||
var metadata = new Metadata
|
||
{
|
||
{ TenantIdMetadataKey, tenantId },
|
||
{ ServiceTokenMetadataKey, _serviceToken },
|
||
};
|
||
return metadata;
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public void Dispose() => _channel.Dispose();
|
||
}
|