169 lines
5.5 KiB
C#
169 lines
5.5 KiB
C#
using System.Collections.Generic;
|
|
using System.Text.Json;
|
|
using LazyBear.MCP.Services.ToolRegistry;
|
|
using RestSharp;
|
|
|
|
namespace LazyBear.MCP.Services.GitLab;
|
|
|
|
/// <summary>
|
|
/// Базовый класс для всех инструментов GitLab
|
|
/// </summary>
|
|
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;
|
|
|
|
/// <summary>
|
|
/// Ошибка инициализации клиента (если возникла)
|
|
/// </summary>
|
|
protected string? ClientInitializationError { get; }
|
|
|
|
/// <summary>
|
|
/// Конструктор
|
|
/// </summary>
|
|
/// <param name="baseUrlConfig">Конфигурация URL</param>
|
|
/// <param name="token">API токен</param>
|
|
/// <param name="registry">Регистратор инструментов</param>
|
|
public GitLabToolsBase(
|
|
string baseUrlConfig,
|
|
string token,
|
|
ToolRegistryService registry)
|
|
{
|
|
_token = token;
|
|
_baseUrlConfig = baseUrlConfig;
|
|
_registry = registry;
|
|
|
|
// Инициализация клиента
|
|
_baseUrl = baseUrlConfig;
|
|
_client = new GitLabApiClient(baseUrlConfig);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Проверка, активирован ли инструмент в TUI
|
|
/// </summary>
|
|
protected bool TryCheckEnabled(string toolName, out string error)
|
|
{
|
|
if (!_registry.IsToolEnabled("GitLab", toolName))
|
|
{
|
|
error = $"Инструмент '{toolName}' модуля GitLab отключён в TUI.";
|
|
return false;
|
|
}
|
|
error = string.Empty;
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Получение клиента RestSharp
|
|
/// </summary>
|
|
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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Создание запроса к GitLab API
|
|
/// </summary>
|
|
protected RestRequest CreateRequest(string resource, RestSharp.Method method = RestSharp.Method.Get)
|
|
{
|
|
var request = _client.GetRequest(resource);
|
|
return request;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Форматирование ошибки ответа от GitLab API
|
|
/// </summary>
|
|
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}";
|
|
}
|
|
|
|
/// <summary>
|
|
/// Форматирование исключения
|
|
/// </summary>
|
|
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}";
|
|
}
|
|
|
|
/// <summary>
|
|
/// Получение вложенного строки из Json
|
|
/// </summary>
|
|
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();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Экстракция текста из комментариев GitLab
|
|
/// </summary>
|
|
protected static string ExtractCommentText(JsonElement body)
|
|
{
|
|
var chunks = new List<string>();
|
|
CollectText(body, chunks);
|
|
return chunks.Count == 0 ? "-" : string.Join(" ", chunks);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Рекурсивный сбор текста из JSON
|
|
/// </summary>
|
|
protected static void CollectText(JsonElement element, List<string> 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);
|
|
}
|
|
}
|
|
}
|
|
} |