using System.Collections.Generic; using System.Text.Json; using LazyBear.MCP.Services.ToolRegistry; using RestSharp; namespace LazyBear.MCP.Services.GitLab; /// /// Базовый класс для всех инструментов GitLab /// public sealed class GitLabToolsBase { protected readonly GitLabApiClient _client; protected readonly string _baseUrl; protected readonly int _perPageDefault; private readonly string _token; private readonly string _baseUrlConfig; private readonly ToolRegistryService _registry; /// /// Ошибка инициализации клиента (если возникла) /// protected string? ClientInitializationError { get; } /// /// Конструктор /// /// Конфигурация URL /// API токен /// Регистратор инструментов public GitLabToolsBase( string baseUrlConfig, string token, ToolRegistryService registry) { _token = token; _baseUrlConfig = baseUrlConfig; _registry = registry; // Инициализация клиента _baseUrl = baseUrlConfig; _client = new GitLabApiClient(baseUrlConfig); } /// /// Проверка, активирован ли инструмент в TUI /// protected bool TryCheckEnabled(string toolName, out string error) { if (!_registry.IsToolEnabled("GitLab", toolName)) { error = $"Инструмент '{toolName}' модуля GitLab отключён в TUI."; return false; } error = string.Empty; return true; } /// /// Получение клиента RestSharp /// protected bool TryGetClient(out GitLabApiClient client, out string error) { client = _client; error = ClientInitializationError is null ? string.Empty : $"GitLab клиент не инициализирован. Проверьте GitLab:Url. Детали: {ClientInitializationError}"; return ClientInitializationError is null; } /// /// Создание запроса к GitLab API /// protected RestRequest CreateRequest(string resource, RestSharp.Method method = RestSharp.Method.Get) { var request = _client.GetRequest(resource); return request; } /// /// Форматирование ошибки ответа от GitLab API /// protected string FormatResponseError(string toolName, RestResponse response, string? resource = null) { var resourcePart = string.IsNullOrWhiteSpace(resource) ? string.Empty : $", resource='{resource}'"; var body = string.IsNullOrWhiteSpace(response.Content) ? "-" : response.Content; return $"Ошибка GitLab в tool '{toolName}'{resourcePart}: status={(int)response.StatusCode}, details={body}"; } /// /// Форматирование исключения /// protected string FormatException(string toolName, Exception exception, string? resource = null) { var resourcePart = string.IsNullOrWhiteSpace(resource) ? string.Empty : $", resource='{resource}'"; return $"Ошибка GitLab в tool '{toolName}'{resourcePart}: {exception.GetType().Name}: {exception.Message}"; } /// /// Получение вложенного строки из Json /// protected static string? GetNestedString(JsonElement element, params string[] path) { var current = element; foreach (var segment in path) { if (!current.TryGetProperty(segment, out current)) { return null; } } return current.ValueKind == JsonValueKind.String ? current.GetString() : current.ToString(); } /// /// Экстракция текста из комментариев GitLab /// protected static string ExtractCommentText(JsonElement body) { var chunks = new List(); CollectText(body, chunks); return chunks.Count == 0 ? "-" : string.Join(" ", chunks); } /// /// Рекурсивный сбор текста из JSON /// protected static void CollectText(JsonElement element, List chunks) { if (element.ValueKind == JsonValueKind.Object) { // Ищем текстовый узел в структуре комментария GitLab if (element.TryGetProperty("body", out var bodyElement) && bodyElement.TryGetProperty("text", out var textElement)) { if (textElement.ValueKind == JsonValueKind.String) { chunks.Add(textElement.GetString() ?? string.Empty); } } foreach (var property in element.EnumerateObject()) { CollectText(property.Value, chunks); } return; } if (element.ValueKind == JsonValueKind.Array) { foreach (var item in element.EnumerateArray()) { CollectText(item, chunks); } } } }