mirror of
https://github.com/RPCS3/discord-bot.git
synced 2026-01-31 01:25:22 +01:00
update GitHubClient, ditch json.net, fix compiler complaints
This commit is contained in:
@@ -2,8 +2,9 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Formatting;
|
||||
using System.Net.Http.Json;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using CompatApiClient;
|
||||
@@ -11,15 +12,13 @@ using CompatApiClient.Compression;
|
||||
using CompatApiClient.Utils;
|
||||
using GithubClient.POCOs;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Newtonsoft.Json;
|
||||
using JsonContractResolver = CompatApiClient.JsonContractResolver;
|
||||
|
||||
namespace GithubClient
|
||||
{
|
||||
public class Client
|
||||
{
|
||||
private readonly HttpClient client;
|
||||
private readonly MediaTypeFormatterCollection formatters;
|
||||
private readonly JsonSerializerOptions jsonOptions;
|
||||
|
||||
private static readonly TimeSpan PrStatusCacheTime = TimeSpan.FromMinutes(3);
|
||||
private static readonly TimeSpan IssueStatusCacheTime = TimeSpan.FromMinutes(30);
|
||||
@@ -33,17 +32,17 @@ namespace GithubClient
|
||||
public Client()
|
||||
{
|
||||
client = HttpClientFactory.Create(new CompressionMessageHandler());
|
||||
var settings = new JsonSerializerSettings
|
||||
jsonOptions = new JsonSerializerOptions
|
||||
{
|
||||
ContractResolver = new JsonContractResolver(NamingStyles.Underscore),
|
||||
NullValueHandling = NullValueHandling.Ignore
|
||||
PropertyNamingPolicy = SpecialJsonNamingPolicy.SnakeCase,
|
||||
IgnoreNullValues = true,
|
||||
IncludeFields = true,
|
||||
};
|
||||
formatters = new MediaTypeFormatterCollection(new[] { new JsonMediaTypeFormatter { SerializerSettings = settings } });
|
||||
}
|
||||
|
||||
public async Task<PrInfo> GetPrInfoAsync(int pr, CancellationToken cancellationToken)
|
||||
public async Task<PrInfo?> GetPrInfoAsync(int pr, CancellationToken cancellationToken)
|
||||
{
|
||||
if (StatusesCache.TryGetValue(pr, out PrInfo result))
|
||||
if (StatusesCache.TryGetValue(pr, out PrInfo? result))
|
||||
{
|
||||
ApiConfig.Log.Debug($"Returned {nameof(PrInfo)} for {pr} from cache");
|
||||
return result;
|
||||
@@ -58,7 +57,7 @@ namespace GithubClient
|
||||
{
|
||||
await response.Content.LoadIntoBufferAsync().ConfigureAwait(false);
|
||||
UpdateRateLimitStats(response.Headers);
|
||||
result = await response.Content.ReadAsAsync<PrInfo>(formatters, cancellationToken).ConfigureAwait(false);
|
||||
result = await response.Content.ReadFromJsonAsync<PrInfo>(jsonOptions, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -80,9 +79,9 @@ namespace GithubClient
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<IssueInfo> GetIssueInfoAsync(int issue, CancellationToken cancellationToken)
|
||||
public async Task<IssueInfo?> GetIssueInfoAsync(int issue, CancellationToken cancellationToken)
|
||||
{
|
||||
if (IssuesCache.TryGetValue(issue, out IssueInfo result))
|
||||
if (IssuesCache.TryGetValue(issue, out IssueInfo? result))
|
||||
{
|
||||
ApiConfig.Log.Debug($"Returned {nameof(IssueInfo)} for {issue} from cache");
|
||||
return result;
|
||||
@@ -97,7 +96,7 @@ namespace GithubClient
|
||||
{
|
||||
await response.Content.LoadIntoBufferAsync().ConfigureAwait(false);
|
||||
UpdateRateLimitStats(response.Headers);
|
||||
result = await response.Content.ReadAsAsync<IssueInfo>(formatters, cancellationToken).ConfigureAwait(false);
|
||||
result = await response.Content.ReadFromJsonAsync<IssueInfo>(jsonOptions, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -119,13 +118,13 @@ namespace GithubClient
|
||||
return result;
|
||||
}
|
||||
|
||||
public Task<List<PrInfo>> GetOpenPrsAsync(CancellationToken cancellationToken) => GetPrsWithStatusAsync("open", cancellationToken);
|
||||
public Task<List<PrInfo>> GetClosedPrsAsync(CancellationToken cancellationToken) => GetPrsWithStatusAsync("closed&sort=updated&direction=desc", cancellationToken);
|
||||
public Task<List<PrInfo>?> GetOpenPrsAsync(CancellationToken cancellationToken) => GetPrsWithStatusAsync("open", cancellationToken);
|
||||
public Task<List<PrInfo>?> GetClosedPrsAsync(CancellationToken cancellationToken) => GetPrsWithStatusAsync("closed&sort=updated&direction=desc", cancellationToken);
|
||||
|
||||
private async Task<List<PrInfo>> GetPrsWithStatusAsync(string status, CancellationToken cancellationToken)
|
||||
private async Task<List<PrInfo>?> GetPrsWithStatusAsync(string status, CancellationToken cancellationToken)
|
||||
{
|
||||
var requestUri = "https://api.github.com/repos/RPCS3/rpcs3/pulls?state=" + status;
|
||||
if (StatusesCache.TryGetValue(requestUri, out List<PrInfo> result))
|
||||
if (StatusesCache.TryGetValue(requestUri, out List<PrInfo>? result))
|
||||
{
|
||||
ApiConfig.Log.Debug("Returned list of opened PRs from cache");
|
||||
return result;
|
||||
@@ -140,7 +139,7 @@ namespace GithubClient
|
||||
{
|
||||
await response.Content.LoadIntoBufferAsync().ConfigureAwait(false);
|
||||
UpdateRateLimitStats(response.Headers);
|
||||
result = await response.Content.ReadAsAsync<List<PrInfo>>(formatters, cancellationToken).ConfigureAwait(false);
|
||||
result = await response.Content.ReadFromJsonAsync<List<PrInfo>>(jsonOptions, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -161,9 +160,9 @@ namespace GithubClient
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<List<StatusInfo>> GetStatusesAsync(string statusesUrl, CancellationToken cancellationToken)
|
||||
public async Task<List<StatusInfo>?> GetStatusesAsync(string statusesUrl, CancellationToken cancellationToken)
|
||||
{
|
||||
if (StatusesCache.TryGetValue(statusesUrl, out List<StatusInfo> result))
|
||||
if (StatusesCache.TryGetValue(statusesUrl, out List<StatusInfo>? result))
|
||||
{
|
||||
ApiConfig.Log.Debug($"Returned cached item for {statusesUrl}");
|
||||
return result;
|
||||
@@ -178,7 +177,7 @@ namespace GithubClient
|
||||
{
|
||||
await response.Content.LoadIntoBufferAsync().ConfigureAwait(false);
|
||||
UpdateRateLimitStats(response.Headers);
|
||||
result = await response.Content.ReadAsAsync<List<StatusInfo>>(formatters, cancellationToken).ConfigureAwait(false);
|
||||
result = await response.Content.ReadFromJsonAsync<List<StatusInfo>>(jsonOptions, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -201,17 +200,17 @@ namespace GithubClient
|
||||
private static void UpdateRateLimitStats(HttpResponseHeaders headers)
|
||||
{
|
||||
if (headers.TryGetValues("X-RateLimit-Limit", out var rateLimitValues)
|
||||
&& rateLimitValues?.FirstOrDefault() is string limitValue
|
||||
&& rateLimitValues.FirstOrDefault() is string limitValue
|
||||
&& int.TryParse(limitValue, out var limit)
|
||||
&& limit > 0)
|
||||
RateLimit = limit;
|
||||
if (headers.TryGetValues("X-RateLimit-Remaining", out var rateLimitRemainingValues)
|
||||
&& rateLimitRemainingValues?.FirstOrDefault() is string remainingValue
|
||||
&& rateLimitRemainingValues.FirstOrDefault() is string remainingValue
|
||||
&& int.TryParse(remainingValue, out var remaining)
|
||||
&& remaining > 0)
|
||||
RateLimitRemaining = remaining;
|
||||
if (headers.TryGetValues("X-RateLimit-Reset", out var rateLimitResetValues)
|
||||
&& rateLimitResetValues?.FirstOrDefault() is string resetValue
|
||||
&& rateLimitResetValues.FirstOrDefault() is string resetValue
|
||||
&& long.TryParse(resetValue, out var resetSeconds)
|
||||
&& resetSeconds > 0)
|
||||
RateLimitResetTime = DateTimeOffset.FromUnixTimeSeconds(resetSeconds).UtcDateTime;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -4,61 +4,61 @@ using System.Diagnostics;
|
||||
namespace GithubClient.POCOs
|
||||
{
|
||||
[DebuggerDisplay("{Body}", Name = "#{Number}")]
|
||||
public class PrInfo
|
||||
public sealed class PrInfo
|
||||
{
|
||||
public string HtmlUrl;
|
||||
public string? HtmlUrl;
|
||||
public int Number;
|
||||
public string State;
|
||||
public string Title;
|
||||
public GithubUser User;
|
||||
public string Body;
|
||||
public string? State;
|
||||
public string? Title;
|
||||
public GithubUser? User;
|
||||
public string? Body;
|
||||
public DateTime CreatedAt;
|
||||
public DateTime? UpdatedAt;
|
||||
public DateTime? ClosedAt;
|
||||
public DateTime? MergedAt;
|
||||
public string MergeCommitSha;
|
||||
public string StatusesUrl;
|
||||
public RefInfo Head;
|
||||
public RefInfo Base;
|
||||
public string? MergeCommitSha;
|
||||
public string? StatusesUrl;
|
||||
public RefInfo? Head;
|
||||
public RefInfo? Base;
|
||||
public int Additions;
|
||||
public int Deletions;
|
||||
public int ChangedFiles;
|
||||
public string Message;
|
||||
public string? Message;
|
||||
}
|
||||
|
||||
public class IssueInfo
|
||||
public sealed class IssueInfo
|
||||
{
|
||||
public string HtmlUrl;
|
||||
public string? HtmlUrl;
|
||||
public int Number;
|
||||
public string State;
|
||||
public string Title;
|
||||
public GithubUser User;
|
||||
public string? State;
|
||||
public string? Title;
|
||||
public GithubUser? User;
|
||||
public DateTime CreatedAt;
|
||||
public DateTime? UpdatedAt;
|
||||
public DateTime? ClosedAt;
|
||||
public DateTime? MergedAt;
|
||||
public string Body;
|
||||
public PullRequestReference PullRequest;
|
||||
public string? Body;
|
||||
public PullRequestReference? PullRequest;
|
||||
}
|
||||
|
||||
public class GithubUser
|
||||
public sealed class GithubUser
|
||||
{
|
||||
public string Login;
|
||||
public string? Login;
|
||||
}
|
||||
|
||||
public class PullRequestReference
|
||||
public sealed class PullRequestReference
|
||||
{
|
||||
public string Url;
|
||||
public string HtmlUrl;
|
||||
public string DiffUrl;
|
||||
public string PatchUrl;
|
||||
public string? Url;
|
||||
public string? HtmlUrl;
|
||||
public string? DiffUrl;
|
||||
public string? PatchUrl;
|
||||
}
|
||||
|
||||
public class RefInfo
|
||||
public sealed class RefInfo
|
||||
{
|
||||
public string Label;
|
||||
public string Ref;
|
||||
public GithubUser User;
|
||||
public string Sha;
|
||||
public string? Label;
|
||||
public string? Ref;
|
||||
public GithubUser? User;
|
||||
public string? Sha;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
|
||||
namespace GithubClient.POCOs
|
||||
{
|
||||
public class StatusInfo
|
||||
public sealed class StatusInfo
|
||||
{
|
||||
public string State; // success
|
||||
public string Description;
|
||||
public string TargetUrl;
|
||||
public string Context; // continuous-integration/appveyor/pr
|
||||
public string? State; // success
|
||||
public string? Description;
|
||||
public string? TargetUrl;
|
||||
public string? Context; // continuous-integration/appveyor/pr
|
||||
public DateTime? CreatedAt;
|
||||
public DateTime? UpdatedAt;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ using System.Text.Json.Serialization;
|
||||
|
||||
namespace IrdLibraryClient.POCOs
|
||||
{
|
||||
public class SearchResult
|
||||
public sealed class SearchResult
|
||||
{
|
||||
public List<SearchResultItem>? Data;
|
||||
public int Draw;
|
||||
@@ -15,7 +15,7 @@ namespace IrdLibraryClient.POCOs
|
||||
public int RecordsTotal;
|
||||
}
|
||||
|
||||
public class SearchResultItem
|
||||
public sealed class SearchResultItem
|
||||
{
|
||||
public string? Id; // product code
|
||||
public string? AppVersion;
|
||||
|
||||
@@ -61,7 +61,7 @@ namespace PsnClient
|
||||
xmlFormatters = new MediaTypeFormatterCollection(new[] {new XmlMediaTypeFormatter {UseXmlSerializer = true}});
|
||||
}
|
||||
|
||||
public string[] GetLocales()
|
||||
public static string[] GetLocales()
|
||||
{
|
||||
// Sony removed the ability to get the full store list, now relying on geolocation service instead
|
||||
return KnownStoreLocales;
|
||||
@@ -126,7 +126,7 @@ namespace PsnClient
|
||||
try
|
||||
{
|
||||
await response.Content.LoadIntoBufferAsync().ConfigureAwait(false);
|
||||
var html = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||||
var html = await response.Content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false);
|
||||
var matches = ContainerIdLink.Matches(html);
|
||||
var result = new List<string>();
|
||||
foreach (Match m in matches)
|
||||
@@ -151,8 +151,8 @@ namespace PsnClient
|
||||
{
|
||||
try
|
||||
{
|
||||
var loc = locale.AsLocaleData();
|
||||
var baseUrl = $"https://store.playstation.com/valkyrie-api/{loc.language}/{loc.country}/999/storefront/{containerId}";
|
||||
var (language, country) = locale.AsLocaleData();
|
||||
var baseUrl = $"https://store.playstation.com/valkyrie-api/{language}/{country}/999/storefront/{containerId}";
|
||||
using var message = new HttpRequestMessage(HttpMethod.Get, baseUrl);
|
||||
using var response = await client.SendAsync(message, cancellationToken).ConfigureAwait(false);
|
||||
try
|
||||
@@ -180,8 +180,8 @@ namespace PsnClient
|
||||
{
|
||||
try
|
||||
{
|
||||
var loc = locale.AsLocaleData();
|
||||
var url = new Uri($"https://store.playstation.com/valkyrie-api/{loc.language}/{loc.country}/999/container/{containerId}");
|
||||
var (language, country) = locale.AsLocaleData();
|
||||
var url = new Uri($"https://store.playstation.com/valkyrie-api/{language}/{country}/999/container/{containerId}");
|
||||
filters ??= new Dictionary<string, string>();
|
||||
filters["start"] = start.ToString();
|
||||
filters["size"] = take.ToString();
|
||||
@@ -214,8 +214,8 @@ namespace PsnClient
|
||||
{
|
||||
try
|
||||
{
|
||||
var loc = locale.AsLocaleData();
|
||||
using var message = new HttpRequestMessage(HttpMethod.Get, $"https://store.playstation.com/valkyrie-api/{loc.language}/{loc.country}/999/resolve/{contentId}?depth={depth}");
|
||||
var (language, country) = locale.AsLocaleData();
|
||||
using var message = new HttpRequestMessage(HttpMethod.Get, $"https://store.playstation.com/valkyrie-api/{language}/{country}/999/resolve/{contentId}?depth={depth}");
|
||||
using var response = await client.SendAsync(message, cancellationToken).ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
@@ -253,7 +253,7 @@ namespace PsnClient
|
||||
await response.Content.LoadIntoBufferAsync().ConfigureAwait(false);
|
||||
patchInfo = await response.Content.ReadAsAsync<TitlePatch>(xmlFormatters, cancellationToken).ConfigureAwait(false);
|
||||
ResponseCache.Set(productId, patchInfo, ResponseCacheDuration);
|
||||
return patchInfo ?? new TitlePatch { Tag = new TitlePatchTag { Packages = new TitlePatchPackage[0], }, };
|
||||
return patchInfo ?? new TitlePatch { Tag = new TitlePatchTag { Packages = Array.Empty<TitlePatchPackage>(), }, };
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -300,10 +300,10 @@ namespace PsnClient
|
||||
{
|
||||
try
|
||||
{
|
||||
var loc = locale.AsLocaleData();
|
||||
var (language, country) = locale.AsLocaleData();
|
||||
var searchId = Uri.EscapeUriString(search);
|
||||
var queryId = Uri.EscapeDataString(searchId);
|
||||
var uri = new Uri($"https://store.playstation.com/valkyrie-api/{loc.language}/{loc.country}/999/faceted-search/{searchId}?query={queryId}&game_content_type=games&size=30&bucket=games&platform=ps3&start=0");
|
||||
var uri = new Uri($"https://store.playstation.com/valkyrie-api/{language}/{country}/999/faceted-search/{searchId}?query={queryId}&game_content_type=games&size=30&bucket=games&platform=ps3&start=0");
|
||||
using var message = new HttpRequestMessage(HttpMethod.Get, uri);
|
||||
using var response = await client.SendAsync(message, cancellationToken).ConfigureAwait(false);
|
||||
try
|
||||
@@ -357,7 +357,7 @@ namespace PsnClient
|
||||
|
||||
private async Task<string> GetSessionCookies(string locale, CancellationToken cancellationToken)
|
||||
{
|
||||
var loc = locale.AsLocaleData();
|
||||
var (language, country) = locale.AsLocaleData();
|
||||
var uri = new Uri("https://store.playstation.com/kamaji/api/valkyrie_storefront/00_09_000/user/session");
|
||||
var tries = 0;
|
||||
do
|
||||
@@ -374,8 +374,8 @@ namespace PsnClient
|
||||
{
|
||||
Content = new FormUrlEncodedContent(new Dictionary<string, string>
|
||||
{
|
||||
["country_code"] = loc.country,
|
||||
["language_code"] = loc.language,
|
||||
["country_code"] = country,
|
||||
["language_code"] = language,
|
||||
})
|
||||
};
|
||||
using (authMessage)
|
||||
@@ -418,7 +418,7 @@ namespace PsnClient
|
||||
return null;
|
||||
|
||||
await response.Content.LoadIntoBufferAsync().ConfigureAwait(false);
|
||||
var data = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||||
var data = await response.Content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false);
|
||||
if (string.IsNullOrEmpty(data))
|
||||
return null;
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace PsnClient.Utils
|
||||
return null;
|
||||
|
||||
if (hexString.Length == 0)
|
||||
return new byte[0];
|
||||
return Array.Empty<byte>();
|
||||
|
||||
if (hexString.Length % 2 != 0)
|
||||
throw new ArgumentException("Invalid hex string format: odd number of octets", nameof(hexString));
|
||||
|
||||
@@ -99,7 +99,7 @@ namespace CompatBot.ThumbScrapper
|
||||
if (ScrapeStateProvider.IsFresh(StoreRefreshTimestamp))
|
||||
return;
|
||||
|
||||
var result = GetLocalesInPreferredOrder(Client.GetLocales());
|
||||
var result = GetLocalesInPreferredOrder(PsnClient.Client.GetLocales());
|
||||
await LockObj.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user