mirror of
https://github.com/NicolasConstant/BirdsiteLive
synced 2025-06-05 21:49:16 +02:00
added federationinfo service
This commit is contained in:
153
src/BirdsiteLive.Domain/TheFedInfoService.cs
Normal file
153
src/BirdsiteLive.Domain/TheFedInfoService.cs
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Net.Http.Headers;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace BirdsiteLive.Domain
|
||||||
|
{
|
||||||
|
public interface ITheFedInfoService
|
||||||
|
{
|
||||||
|
Task<List<BslInstanceInfo>> GetBslInstanceListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TheFedInfoService : ITheFedInfoService
|
||||||
|
{
|
||||||
|
private readonly IHttpClientFactory _httpClientFactory;
|
||||||
|
|
||||||
|
#region Ctor
|
||||||
|
public TheFedInfoService(IHttpClientFactory httpClientFactory)
|
||||||
|
{
|
||||||
|
_httpClientFactory = httpClientFactory;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public async Task<List<BslInstanceInfo>> GetBslInstanceListAsync()
|
||||||
|
{
|
||||||
|
var cancellationToken = CancellationToken.None;
|
||||||
|
|
||||||
|
var result = await CallGraphQlAsync<MyResponseData>(
|
||||||
|
new Uri("https://the-federation.info/graphql"),
|
||||||
|
HttpMethod.Get,
|
||||||
|
"query ($platform: String!) { nodes(platform: $platform) { host, version } }",
|
||||||
|
new
|
||||||
|
{
|
||||||
|
platform = "birdsitelive",
|
||||||
|
},
|
||||||
|
cancellationToken);
|
||||||
|
|
||||||
|
var convertedResults = ConvertResults(result);
|
||||||
|
return convertedResults;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<BslInstanceInfo> ConvertResults(GraphQLResponse<MyResponseData> qlData)
|
||||||
|
{
|
||||||
|
var results = new List<BslInstanceInfo>();
|
||||||
|
|
||||||
|
foreach (var instanceInfo in qlData.Data.Nodes)
|
||||||
|
{
|
||||||
|
var rawVersion = instanceInfo.Version.Split('+').FirstOrDefault();
|
||||||
|
var version = Version.Parse(rawVersion);
|
||||||
|
|
||||||
|
var instance = new BslInstanceInfo
|
||||||
|
{
|
||||||
|
Host = instanceInfo.Host,
|
||||||
|
Version = version
|
||||||
|
};
|
||||||
|
results.Add(instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<GraphQLResponse<TResponse>> CallGraphQlAsync<TResponse>(Uri endpoint, HttpMethod method, string query, object variables, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var content = new StringContent(SerializeGraphQlCall(query, variables), Encoding.UTF8, "application/json");
|
||||||
|
var httpRequestMessage = new HttpRequestMessage
|
||||||
|
{
|
||||||
|
Method = method,
|
||||||
|
Content = content,
|
||||||
|
RequestUri = endpoint,
|
||||||
|
};
|
||||||
|
//add authorization headers if necessary here
|
||||||
|
httpRequestMessage.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
|
||||||
|
var httpClient = _httpClientFactory.CreateClient();
|
||||||
|
using (var response = await httpClient.SendAsync(httpRequestMessage, cancellationToken))
|
||||||
|
{
|
||||||
|
//if (response.IsSuccessStatusCode)
|
||||||
|
if (response?.Content.Headers.ContentType?.MediaType == "application/json")
|
||||||
|
{
|
||||||
|
var responseString = await response.Content.ReadAsStringAsync(); //cancellationToken supported for .NET 5/6
|
||||||
|
return DeserializeGraphQlCall<TResponse>(responseString);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new ApplicationException($"Unable to contact '{endpoint}': {response.StatusCode} - {response.ReasonPhrase}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string SerializeGraphQlCall(string query, object variables)
|
||||||
|
{
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
var textWriter = new StringWriter(sb);
|
||||||
|
var serializer = new JsonSerializer();
|
||||||
|
serializer.Serialize(textWriter, new
|
||||||
|
{
|
||||||
|
query = query,
|
||||||
|
variables = variables,
|
||||||
|
});
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private GraphQLResponse<TResponse> DeserializeGraphQlCall<TResponse>(string response)
|
||||||
|
{
|
||||||
|
var serializer = new JsonSerializer();
|
||||||
|
var stringReader = new StringReader(response);
|
||||||
|
var jsonReader = new JsonTextReader(stringReader);
|
||||||
|
var result = serializer.Deserialize<GraphQLResponse<TResponse>>(jsonReader);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class GraphQLResponse<TResponse>
|
||||||
|
{
|
||||||
|
public List<GraphQLError> Errors { get; set; }
|
||||||
|
public TResponse Data { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private class GraphQLError
|
||||||
|
{
|
||||||
|
public string Message { get; set; }
|
||||||
|
public List<GraphQLErrorLocation> Locations { get; set; }
|
||||||
|
public List<object> Path { get; set; } //either int or string
|
||||||
|
}
|
||||||
|
|
||||||
|
private class GraphQLErrorLocation
|
||||||
|
{
|
||||||
|
public int Line { get; set; }
|
||||||
|
public int Column { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private class MyResponseData
|
||||||
|
{
|
||||||
|
public Node[] Nodes { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private class Node
|
||||||
|
{
|
||||||
|
public string Host { get; set; }
|
||||||
|
public string Version { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class BslInstanceInfo
|
||||||
|
{
|
||||||
|
public string Host { get; set; }
|
||||||
|
public Version Version { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,34 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using Moq;
|
||||||
|
|
||||||
|
namespace BirdsiteLive.Domain.Tests
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class TheFedInfoServiceTests
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public async Task GetBslInstanceListAsyncTest()
|
||||||
|
{
|
||||||
|
var httpClientFactoryMock = new Mock<IHttpClientFactory>();
|
||||||
|
httpClientFactoryMock
|
||||||
|
.Setup(x => x.CreateClient(It.IsAny<string>()))
|
||||||
|
.Returns(new HttpClient());
|
||||||
|
|
||||||
|
var service = new TheFedInfoService(httpClientFactoryMock.Object);
|
||||||
|
|
||||||
|
var bslInstanceList = await service.GetBslInstanceListAsync();
|
||||||
|
|
||||||
|
Assert.IsTrue(bslInstanceList.Count > 0);
|
||||||
|
|
||||||
|
foreach (var instanceInfo in bslInstanceList)
|
||||||
|
{
|
||||||
|
Assert.IsFalse(string.IsNullOrWhiteSpace(instanceInfo.Host));
|
||||||
|
Assert.IsTrue(instanceInfo.Version > new Version(0, 1, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user