forked from RPCS3/discord-bot
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathIrdClient.cs
139 lines (129 loc) · 5.86 KB
/
IrdClient.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Tasks;
using CompatApiClient;
using CompatApiClient.Compression;
using IrdLibraryClient.IrdFormat;
using IrdLibraryClient.POCOs;
using Microsoft.Extensions.Caching.Memory;
namespace IrdLibraryClient
{
public class IrdClient
{
private static readonly Uri BaseDownloadUri = new("https://github.com/FlexBy420/playstation_3_ird_database/raw/main/");
private static readonly HttpClient Client = HttpClientFactory.Create(new CompressionMessageHandler());
private static readonly JsonSerializerOptions JsonOptions= new()
{
PropertyNamingPolicy = JsonNamingPolicy.KebabCaseLower,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
IncludeFields = true,
};
private static readonly MemoryCache JsonCache = new(new MemoryCacheOptions{ ExpirationScanFrequency = TimeSpan.FromHours(1) });
public static readonly Uri JsonUrl = new("https://flexby420.github.io/playstation_3_ird_database/all.json");
public async Task<List<IrdInfo>> SearchAsync(string query, CancellationToken cancellationToken)
{
List<IrdInfo> result = [];
if (!JsonCache.TryGetValue("json", out Dictionary<string, List<IrdInfo>>? irdData)
|| irdData is not { Count: > 0 })
{
try
{
using var response = await Client.GetAsync(JsonUrl, cancellationToken).ConfigureAwait(false);
if (!response.IsSuccessStatusCode)
{
ApiConfig.Log.Error($"Failed to fetch IRD data: {response.StatusCode}");
return result;
}
var jsonResult = await response.Content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false);
irdData = JsonSerializer.Deserialize<Dictionary<string, List<IrdInfo>>>(jsonResult, JsonOptions);
JsonCache.Set("json", irdData, TimeSpan.FromHours(4));
}
catch (Exception e)
{
ApiConfig.Log.Error(e, "Failed to fetch IRD data.");
return result;
}
}
if (irdData is null)
{
ApiConfig.Log.Error("Failed to deserialize IRD JSON data.");
return result;
}
if (irdData.TryGetValue(query.ToUpperInvariant(), out var items))
result.AddRange(items);
result.AddRange(
from lst in irdData.Values
from irdInfo in lst
where irdInfo.Title?.Contains(query, StringComparison.OrdinalIgnoreCase) ?? false
select irdInfo
);
return result;
}
public async Task<List<Ird>> DownloadAsync(string productCode, string localCachePath, CancellationToken cancellationToken)
{
var result = new List<Ird>();
try
{
var searchResults = await SearchAsync(productCode, cancellationToken).ConfigureAwait(false);
if (searchResults is not {Count: >0})
{
ApiConfig.Log.Debug($"No IRD files found for {productCode}");
return result;
}
foreach (var item in searchResults)
{
var localFilePath = Path.Combine(localCachePath, $"{productCode}-{item.Link.Split('/').Last()}.ird");
if (File.Exists(localFilePath))
{
var irdData = await File.ReadAllBytesAsync(localFilePath, cancellationToken).ConfigureAwait(false);
try
{
result.Add(IrdParser.Parse(irdData));
}
catch (Exception e)
{
ApiConfig.Log.Warn(e, $"Failed to parse locally cached IRD file {localFilePath}");
try { File.Delete(localFilePath); } catch {}
}
}
else
{
try
{
var downloadLink = GetDownloadLink(item.Link);
var fileBytes = await Client.GetByteArrayAsync(downloadLink, cancellationToken).ConfigureAwait(false);
await File.WriteAllBytesAsync(localFilePath, fileBytes, cancellationToken).ConfigureAwait(false);
result.Add(IrdParser.Parse(fileBytes));
}
catch (Exception e)
{
ApiConfig.Log.Warn(e, $"Failed to download {item.Link}: {e.Message}");
}
}
}
ApiConfig.Log.Debug($"Returning {result.Count} .ird files for {productCode}");
return result;
}
catch (Exception e)
{
ApiConfig.Log.Error(e);
return result;
}
}
private static string EscapeSegments(string relativePath)
{
var segments = relativePath.Split('/');
for (var i = 0; i < segments.Length; i++)
segments[i] = Uri.EscapeDataString(segments[i]);
return string.Join("/", segments);
}
public static Uri GetDownloadLink(string relativeLink) => new(BaseDownloadUri, EscapeSegments(relativeLink));
public static string GetEscapedDownloadLink(string relativeLink) => GetDownloadLink(relativeLink).AbsoluteUri;
}
}