Skip to content

Commit

Permalink
add support for NativeAOT
Browse files Browse the repository at this point in the history
now you can use ProjBobcat with NativeAOT!
remove icrosoft.Extensions.DependencyInjection.Abstractions
change the way of using HttpClientHelper
remove ServiceHelper
update readme
  • Loading branch information
laolarou726 committed Apr 2, 2023
1 parent 365f47e commit 40b41fb
Show file tree
Hide file tree
Showing 69 changed files with 478 additions and 160 deletions.
10 changes: 8 additions & 2 deletions ProjBobcat/ProjBobcat/Class/Helper/AuthPropertyHelper.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Text.Json.Serialization;
using ProjBobcat.Class.Model;
using ProjBobcat.Class.Model.LauncherProfile;
using ProjBobcat.Class.Model.YggdrasilAuth;

namespace ProjBobcat.Class.Helper;

[JsonSerializable(typeof(Dictionary<string, string[]>))]
partial class UserPropertiesContext : JsonSerializerContext
{
}

/// <summary>
/// AuthProperty工具类
/// </summary>
Expand All @@ -17,7 +23,7 @@ public static class AuthPropertyHelper
/// </summary>
/// <param name="properties">Property 集合</param>
/// <returns>解析好的User Property</returns>
public static string ResolveUserProperties(this IEnumerable<PropertyModel> properties)
public static string ResolveUserProperties(this IEnumerable<PropertyModel>? properties)
{
if (properties == null) return "{}";

Expand All @@ -26,7 +32,7 @@ public static string ResolveUserProperties(this IEnumerable<PropertyModel> prope
item => item.Name,
item => new[] { item.Value });

return JsonSerializer.Serialize(keyValues);
return JsonSerializer.Serialize(keyValues, UserPropertiesContext.Default.DictionaryStringStringArray);
}


Expand Down
73 changes: 59 additions & 14 deletions ProjBobcat/ProjBobcat/Class/Helper/CurseForgeAPIHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,66 @@
using System.Net.Http.Json;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using ProjBobcat.Class.Model.CurseForge;
using ProjBobcat.Class.Model.CurseForge.API;

namespace ProjBobcat.Class.Helper;

#region Temp Models

record AddonInfoReqModel(IEnumerable<int> modIds);


[JsonSerializable(typeof(AddonInfoReqModel))]
partial class AddonInfoReqModelContext : JsonSerializerContext
{
}

[JsonSerializable(typeof(DataModelWithPagination<CurseForgeAddonInfo[]>))]
partial class SearchAddonsResultModelContext : JsonSerializerContext
{
}

[JsonSerializable(typeof(DataModel<CurseForgeAddonInfo>))]
partial class GetAddonResultModelContext : JsonSerializerContext
{
}

[JsonSerializable(typeof(DataModel<CurseForgeAddonInfo[]>))]
partial class GetAddonsResultModelContext : JsonSerializerContext
{
}

[JsonSerializable(typeof(DataModel<CurseForgeLatestFileModel[]>))]
partial class GetAddonFilesResultModelContext : JsonSerializerContext
{
}

[JsonSerializable(typeof(DataModel<CurseForgeSearchCategoryModel[]>))]
partial class GetCategoriesResultContext : JsonSerializerContext
{
}

[JsonSerializable(typeof(DataModel<CurseForgeFeaturedAddonModel>))]
partial class GetFeaturedAddonsResultContext : JsonSerializerContext
{
}

[JsonSerializable(typeof(DataModel<string>))]
partial class DataModelStringResultContext : JsonSerializerContext
{
}

#endregion

public static class CurseForgeAPIHelper
{
const string BaseUrl = "https://api.curseforge.com/v1";

static string ApiKey { get; set; }
static HttpClient Client => HttpClientHelper.GetNewClient(HttpClientHelper.DefaultClientName);
static HttpClient Client => HttpClientHelper.DefaultClient;

static HttpRequestMessage Req(HttpMethod method, string url)
{
Expand All @@ -37,7 +85,7 @@ public static void SetApiKey(string apiKey)
using var req = Req(HttpMethod.Get, reqUrl);
using var res = await Client.SendAsync(req);

return await res.Content.ReadFromJsonAsync<DataModelWithPagination<CurseForgeAddonInfo[]>>();
return await res.Content.ReadFromJsonAsync(SearchAddonsResultModelContext.Default.DataModelWithPaginationCurseForgeAddonInfoArray);
}

public static async Task<CurseForgeAddonInfo?> GetAddon(int addonId)
Expand All @@ -47,16 +95,13 @@ public static void SetApiKey(string apiKey)
using var req = Req(HttpMethod.Get, reqUrl);
using var res = await Client.SendAsync(req);

return (await res.Content.ReadFromJsonAsync<DataModel<CurseForgeAddonInfo>>())?.Data;
return (await res.Content.ReadFromJsonAsync(GetAddonResultModelContext.Default.DataModelCurseForgeAddonInfo))?.Data;
}

public static async Task<CurseForgeAddonInfo[]?> GetAddons(IEnumerable<int> addonIds)
{
const string reqUrl = $"{BaseUrl}/mods";
var data = JsonSerializer.Serialize(new
{
modIds = addonIds
});
var data = JsonSerializer.Serialize(new AddonInfoReqModel(addonIds), AddonInfoReqModelContext.Default.AddonInfoReqModel);

using var req = Req(HttpMethod.Post, reqUrl);
req.Content = new StringContent(data, Encoding.UTF8, "application/json");
Expand All @@ -65,7 +110,7 @@ public static void SetApiKey(string apiKey)

res.EnsureSuccessStatusCode();

return (await res.Content.ReadFromJsonAsync<DataModel<CurseForgeAddonInfo[]>>())?.Data;
return (await res.Content.ReadFromJsonAsync(GetAddonsResultModelContext.Default.DataModelCurseForgeAddonInfoArray))?.Data;
}

public static async Task<CurseForgeLatestFileModel[]?> GetAddonFiles(int addonId)
Expand All @@ -75,7 +120,7 @@ public static void SetApiKey(string apiKey)
using var req = Req(HttpMethod.Get, reqUrl);
using var res = await Client.SendAsync(req);

return (await res.Content.ReadFromJsonAsync<DataModel<CurseForgeLatestFileModel[]>>())?.Data;
return (await res.Content.ReadFromJsonAsync(GetAddonFilesResultModelContext.Default.DataModelCurseForgeLatestFileModelArray))?.Data;
}

public static async Task<CurseForgeSearchCategoryModel[]?> GetCategories(int gameId = 432)
Expand All @@ -85,21 +130,21 @@ public static void SetApiKey(string apiKey)
using var req = Req(HttpMethod.Get, reqUrl);
using var res = await Client.SendAsync(req);

return (await res.Content.ReadFromJsonAsync<DataModel<CurseForgeSearchCategoryModel[]>>())?.Data;
return (await res.Content.ReadFromJsonAsync(GetCategoriesResultContext.Default.DataModelCurseForgeSearchCategoryModelArray))?.Data;
}

public static async Task<CurseForgeFeaturedAddonModel?> GetFeaturedAddons(FeaturedQueryOptions options)
{
const string reqUrl = $"{BaseUrl}/mods/featured";
var reqJson = JsonSerializer.Serialize(options);
var reqJson = JsonSerializer.Serialize(options, FeaturedQueryOptionsContext.Default.FeaturedQueryOptions);

using var req = Req(HttpMethod.Post, reqUrl);
req.Content = new StringContent(reqJson, Encoding.UTF8, "application/json");

using var res = await Client.SendAsync(req);
res.EnsureSuccessStatusCode();

return (await res.Content.ReadFromJsonAsync<DataModel<CurseForgeFeaturedAddonModel>>())?.Data;
return (await res.Content.ReadFromJsonAsync(GetFeaturedAddonsResultContext.Default.DataModelCurseForgeFeaturedAddonModel))?.Data;
}

public static async Task<string?> GetAddonDownloadUrl(long addonId, long fileId)
Expand All @@ -110,7 +155,7 @@ public static void SetApiKey(string apiKey)
using var res = await Client.SendAsync(req);
res.EnsureSuccessStatusCode();

return (await res.Content.ReadFromJsonAsync<DataModel<string>>())?.Data;
return (await res.Content.ReadFromJsonAsync(DataModelStringResultContext.Default.DataModelString))?.Data;
}

public static async Task<string?> GetAddonDescriptionHtml(long addonId)
Expand All @@ -121,6 +166,6 @@ public static void SetApiKey(string apiKey)
using var res = await Client.SendAsync(req);
res.EnsureSuccessStatusCode();

return (await res.Content.ReadFromJsonAsync<DataModel<string>>())?.Data;
return (await res.Content.ReadFromJsonAsync(DataModelStringResultContext.Default.DataModelString))?.Data;
}
}
7 changes: 3 additions & 4 deletions ProjBobcat/ProjBobcat/Class/Helper/DownloadHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public static class DownloadHelper
/// </summary>
public static int DownloadThread { get; set; } = 8;

static HttpClient DataClient => HttpClientHelper.GetNewClient(HttpClientHelper.DataClientName);
static HttpClient DataClient => HttpClientHelper.DataClient;

#region 下载数据

Expand Down Expand Up @@ -218,10 +218,9 @@ public static async Task AdvancedDownloadListFile(IEnumerable<DownloadFile> file

#region 分片下载

static HttpClient HeadClient => HttpClientHelper.GetNewClient(HttpClientHelper.HeadClientName);
static HttpClient HeadClient => HttpClientHelper.HeadClient;

static HttpClient MultiPartClient =>
HttpClientHelper.GetNewClient(HttpClientHelper.MultiPartClientName);
static HttpClient MultiPartClient => HttpClientHelper.MultiPartClient;

static readonly MemoryPool<byte> Pool = MemoryPool<byte>.Shared;

Expand Down
12 changes: 6 additions & 6 deletions ProjBobcat/ProjBobcat/Class/Helper/GameResourcesResolveHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,19 +78,19 @@ public static async IAsyncEnumerable<GameModResolvedInfo> ResolveModListAsync(IE
async Task<GameModResolvedInfo?> GetNewModInfo(IArchiveEntry entry)
{
await using var stream = entry.OpenEntryStream();
var doc = await JsonDocument.ParseAsync(stream);
var doc = await JsonDocument.ParseAsync(stream, cancellationToken: ct);

List<GameModInfoModel>? model = null;
switch (doc.RootElement.ValueKind)
{
case JsonValueKind.Object:
var val = doc.RootElement.Deserialize<GameModInfoModel>();
var val = doc.RootElement.Deserialize(GameModInfoModelContext.Default.GameModInfoModel);

if (val != null) model = new List<GameModInfoModel> { val };

break;
case JsonValueKind.Array:
model = doc.RootElement.Deserialize<List<GameModInfoModel>>();
model = doc.RootElement.Deserialize(GameModInfoModelContext.Default.ListGameModInfoModel) ?? new List<GameModInfoModel>();
break;
}

Expand Down Expand Up @@ -127,7 +127,7 @@ public static async IAsyncEnumerable<GameModResolvedInfo> ResolveModListAsync(IE
async Task<GameModResolvedInfo> GetFabricModInfo(IArchiveEntry entry)
{
await using var stream = entry.OpenEntryStream();
var tempModel = await JsonSerializer.DeserializeAsync<FabricModInfoModel>(stream);
var tempModel = await JsonSerializer.DeserializeAsync(stream, FabricModInfoModelContext.Default.FabricModInfoModel, ct);

var author = tempModel?.Authors?.Any() ?? false
? string.Join(',', tempModel.Authors)
Expand Down Expand Up @@ -204,7 +204,7 @@ public static async IAsyncEnumerable<GameResourcePackResolvedInfo> ResolveResour
if (packInfoEntry != null)
{
await using var stream = packInfoEntry.OpenEntryStream();
var model = await JsonSerializer.DeserializeAsync<GameResourcePackModel>(stream);
var model = await JsonSerializer.DeserializeAsync(stream, GameResourcePackModelContext.Default.GameResourcePackModel, ct);

description = model?.Pack?.Description;
version = model?.Pack?.PackFormat ?? -1;
Expand All @@ -228,7 +228,7 @@ public static async IAsyncEnumerable<GameResourcePackResolvedInfo> ResolveResour
if (File.Exists(infoPath))
{
await using var contentStream = File.OpenRead(infoPath);
var model = await JsonSerializer.DeserializeAsync<GameResourcePackModel>(contentStream);
var model = await JsonSerializer.DeserializeAsync(contentStream, GameResourcePackModelContext.Default.GameResourcePackModel, ct);

description = model?.Pack?.Description;
version = model?.Pack?.PackFormat ?? -1;
Expand Down
40 changes: 31 additions & 9 deletions ProjBobcat/ProjBobcat/Class/Helper/HttpClientHelper.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
using System.Net.Http;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Net.Http;
using ProjBobcat.Handler;

namespace ProjBobcat.Class.Helper;
Expand All @@ -9,18 +9,39 @@ namespace ProjBobcat.Class.Helper;
/// </summary>
public static class HttpClientHelper
{
public const string DefaultClientName = "DefaultClient";
public const string DataClientName = "DataClient";
public const string HeadClientName = "HeadClient";
public const string MultiPartClientName = "MultiPartClient";
static readonly Lazy<HttpClient> DefaultClientFactory = new (HttpClientFactory);
static readonly Lazy<HttpClient> DataClientFactory = new(HttpClientFactory);
static readonly Lazy<HttpClient> HeadClientFactory = new(HttpClientFactory);
static readonly Lazy<HttpClient> MultiPartClientFactory = new(() =>
{
var client = HttpClientFactory();

client.DefaultRequestHeaders.ConnectionClose = false;

return client;
});

public static HttpClient DefaultClient => DefaultClientFactory.Value;
public static HttpClient DataClient => DataClientFactory.Value;
public static HttpClient HeadClient => HeadClientFactory.Value;
public static HttpClient MultiPartClient => MultiPartClientFactory.Value;

static HttpClient HttpClientFactory()
{
var handlers = new RedirectHandler(new RetryHandler(new HttpClientHandler { AllowAutoRedirect = false }));
var httpClient = new HttpClient(handlers);

httpClient.DefaultRequestHeaders.UserAgent.ParseAdd(Ua);

return httpClient;
}

/// <summary>
/// 获取或设置用户代理信息。
/// </summary>
public static string Ua { get; set; } = "ProjBobcat";

public static IHttpClientFactory HttpClientFactory { get; private set; }


/*
public static void Init()
{
var arr = new[] { DefaultClientName, DataClientName, HeadClientName, MultiPartClientName };
Expand Down Expand Up @@ -53,4 +74,5 @@ public static HttpClient GetNewClient(string name)
{
return HttpClientFactory.CreateClient(name);
}
*/
}
2 changes: 1 addition & 1 deletion ProjBobcat/ProjBobcat/Class/Helper/HttpHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public static class HttpHelper
static readonly Regex UriRegex = new(UriRegexStr, RegexOptions.Compiled);
#pragma warning restore SYSLIB1045 // 转换为“GeneratedRegexAttribute”。

static HttpClient Client => HttpClientHelper.GetNewClient(HttpClientHelper.DefaultClientName);
static HttpClient Client => HttpClientHelper.DefaultClient;

/// <summary>
/// 正则匹配Uri
Expand Down
13 changes: 8 additions & 5 deletions ProjBobcat/ProjBobcat/Class/Helper/JsonHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@ namespace ProjBobcat.Class.Helper;

public static class JsonHelper
{
public static readonly JsonSerializerOptions CamelCasePropertyNamesSettings = new()
public static JsonSerializerOptions CamelCasePropertyNamesSettings()
{
WriteIndented = true,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
MaxDepth = 100
};
return new()
{
WriteIndented = true,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
MaxDepth = 100
};
}
}
6 changes: 4 additions & 2 deletions ProjBobcat/ProjBobcat/Class/Helper/JwtTokenHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Linq;
using System.Security.Claims;
using System.Text.Json;
using ProjBobcat.Class.Model.JsonContexts;

namespace ProjBobcat.Class.Helper;

Expand All @@ -12,8 +13,9 @@ static IEnumerable<Claim> ParseClaimsFromJwt(string jwt)
{
var payload = jwt.Split('.')[1];
var jsonBytes = Convert.FromBase64String(ReformatBase64String(payload));
var keyValuePairs = JsonSerializer.Deserialize<Dictionary<string, object>>(jsonBytes);
return keyValuePairs.Select(kvp => new Claim(kvp.Key, kvp.Value.ToString()));
var keyValuePairs = JsonSerializer.Deserialize(jsonBytes, JsonElementContext.Default.JsonElement);

return keyValuePairs.EnumerateObject().Select(p => new Claim(p.Name, p.Value.ToString()));
}

static string ReformatBase64String(string str)
Expand Down
Loading

0 comments on commit 40b41fb

Please sign in to comment.