155 lines
5.0 KiB
C#
155 lines
5.0 KiB
C#
using System.Net.Http;
|
|
using System.Text.Json;
|
|
|
|
namespace LazyBear.Confluence;
|
|
|
|
public static class ConfluenceClientFactory
|
|
{
|
|
public static HttpClient CreateClient(string baseUrl, HttpClientHandler? handler = null)
|
|
{
|
|
handler ??= new HttpClientHandler();
|
|
|
|
return new HttpClient(handler)
|
|
{
|
|
BaseAddress = new Uri(baseUrl.TrimEnd('/')),
|
|
DefaultRequestHeaders =
|
|
{
|
|
HttpHeaders
|
|
{
|
|
["User-Agent"] = "LazyBear-Confluence-MCP/1.0",
|
|
["Accept"] = "application/json"
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
public static ConfluenceHttpClientProvider CreateProvider(string baseUrl, string? token = null, HttpClientHandler? handler = null)
|
|
{
|
|
var httpHandler = handler ?? new HttpClientHandler();
|
|
var httpClient = CreateClient(baseUrl, httpHandler);
|
|
|
|
return new ConfluenceHttpClientProvider(httpClient, baseUrl, token);
|
|
}
|
|
}
|
|
|
|
public sealed class ConfluenceHttpClientProvider
|
|
{
|
|
public HttpClient Client { get; }
|
|
public string BaseUrl => HttpBaseAddress?.Root ?? string.Empty;
|
|
public string? AccessToken { get; }
|
|
public string? InitializationError { get; }
|
|
|
|
private Uri? HttpBaseAddress;
|
|
|
|
public ConfluenceHttpClientProvider(HttpClient client, string baseUrl, string? token = null)
|
|
{
|
|
Client = client;
|
|
HttpBaseAddress = new Uri(baseUrl.TrimEnd('/'));
|
|
AccessToken = token;
|
|
}
|
|
|
|
public ConcurrentDictionary<string, JsonElement> Cache { get; } = new();
|
|
|
|
public async Task<T?> GetJsonAsync<T>(HttpRequestMessage request) where T : class
|
|
{
|
|
using var response = await Client.SendAsync(request).ConfigureAwait(false);
|
|
|
|
if (!response.IsSuccessStatusCode)
|
|
{
|
|
if (response.StatusCode == System.Net.HttpStatusCode.NotFound)
|
|
{
|
|
return default;
|
|
}
|
|
|
|
var errorBody = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
|
|
throw new HttpRequestException($"[{request.RequestMethod}] {request.RequestUri}: {response.StatusCode} {errorBody}");
|
|
}
|
|
|
|
return await JsonSerializer.DeserializeAsync<T>(response.Content, request, JsonDefaults.DefaultSerializerOptions)
|
|
.ConfigureAwait(false);
|
|
}
|
|
|
|
public async Task<JsonElement?> GetJsonAsync(HttpRequestMessage request)
|
|
{
|
|
if (Cache.TryGetValue(request.RequestUri!.ToString(), out var cached))
|
|
{
|
|
return cached;
|
|
}
|
|
|
|
using var response = await Client.SendAsync(request).ConfigureAwait(false);
|
|
|
|
if (!response.IsSuccessStatusCode)
|
|
{
|
|
if (response.StatusCode == System.Net.HttpStatusCode.NotFound)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
var errorBody = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
|
|
throw new HttpRequestException($"[{request.RequestMethod}] {request.RequestUri}: {response.StatusCode} {errorBody}");
|
|
}
|
|
|
|
var json = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
|
|
var element = JsonDocument.Parse(json).RootElement;
|
|
|
|
Cache[request.RequestUri!.ToString()] = element;
|
|
return element;
|
|
}
|
|
|
|
public HttpRequestMessage CreateGetRequest(string resource)
|
|
{
|
|
return new HttpRequestMessage(HttpMethod.Get, HttpBaseAddress + resource);
|
|
}
|
|
|
|
public HttpRequestMessage CreatePostRequest(string resource, object? body = null)
|
|
{
|
|
var request = new HttpRequestMessage(HttpMethod.Post, HttpBaseAddress + resource);
|
|
request.Content = new StringContent(JsonSerializer.Serialize(body), System.Text.Encoding.UTF8, "application/json");
|
|
return request;
|
|
}
|
|
|
|
public HttpRequestMessage CreatePutRequest(string resource, object? body = null)
|
|
{
|
|
var request = new HttpRequestMessage(HttpMethod.Put, HttpBaseAddress + resource);
|
|
request.Content = new StringContent(JsonSerializer.Serialize(body), System.Text.Encoding.UTF8, "application/json");
|
|
return request;
|
|
}
|
|
|
|
public HttpRequestMessage CreateDeleteRequest(string resource)
|
|
{
|
|
return new HttpRequestMessage(HttpMethod.Delete, HttpBaseAddress + resource);
|
|
}
|
|
|
|
public void SetAccessToken(string token)
|
|
{
|
|
AccessToken = token;
|
|
}
|
|
|
|
public void SetRequestHeaders(HttpHeaders headers)
|
|
{
|
|
var cloned = Client.DefaultRequestHeaders.Clone();
|
|
foreach (var header in headers)
|
|
{
|
|
cloned.Add(header.Key, header.Value);
|
|
}
|
|
Client.DefaultRequestHeaders = cloned;
|
|
}
|
|
|
|
public void AddRequestHeader(string name, params string[] values)
|
|
{
|
|
foreach (var value in values)
|
|
{
|
|
Client.DefaultRequestHeaders.Add(name, value);
|
|
}
|
|
}
|
|
|
|
private class JsonDefaults
|
|
{
|
|
public static readonly JsonSerializerOptions DefaultSerializerOptions = new()
|
|
{
|
|
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
|
Converters = { new JsonStringEnumConverter() }
|
|
};
|
|
}
|
|
}
|