diff --git a/IGDB.Tests/Dumps.cs b/IGDB.Tests/Dumps.cs new file mode 100644 index 0000000..d648fda --- /dev/null +++ b/IGDB.Tests/Dumps.cs @@ -0,0 +1,40 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using IGDB.Models; +using RestEase; +using Xunit; + +namespace IGDB.Tests +{ + public class Dumps + { + IGDBClient _api; + + public Dumps() + { + _api = new IGDB.IGDBClient( + Environment.GetEnvironmentVariable("IGDB_CLIENT_ID"), + Environment.GetEnvironmentVariable("IGDB_CLIENT_SECRET") + ); + } + + [Fact] + public async Task ShouldReturnDumpsList() + { + var dumps = await _api.GetDataDumpsAsync(); + + Assert.NotNull(dumps); + Assert.True(dumps.Length > 10); + } + + [Fact] + public async Task ShouldReturnGamesEndpointDump() + { + var gameDump = await _api.GetDataDumpEndpointAsync("games"); + + Assert.NotNull(gameDump); + Assert.NotNull(gameDump.S3Url); + } + } +} \ No newline at end of file diff --git a/IGDB/IGDBApi.cs b/IGDB/IGDBApi.cs index b6ceb50..ed84fb0 100644 --- a/IGDB/IGDBApi.cs +++ b/IGDB/IGDBApi.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.IO; using System.Threading.Tasks; using IGDB.Models; using Newtonsoft.Json; @@ -37,6 +38,18 @@ public interface IGDBApi /// Array of IGDB models of the specified type [Post("/{endpoint}/count")] Task CountAsync([Path] string endpoint, [Body] string query = null); + + /// + /// Retrieves list of available data dumps (IGDB Partners only) + /// + [Get("/dumps")] + Task GetDataDumpsAsync(); + + /// + /// Retrieves the download URL of a data dump (IGDB Partners only). Use the S3Url to download the dump (link expires after 5 minutes). + /// + [Get("/dumps/{endpoint}")] + Task GetDataDumpForEndpointAsync([Path] string endpoint); } public sealed class IGDBClient @@ -150,6 +163,48 @@ public async Task CountAsync(string endpoint, string query = null } } + public async Task GetDataDumpsAsync() + { + try + { + return await _api.GetDataDumpsAsync(); + } + catch (ApiException apiEx) + { + // Acquire new token and retry request (once) + if (IsInvalidTokenResponse(apiEx)) + { + await _tokenManager.RefreshTokenAsync(); + + return await _api.GetDataDumpsAsync(); + } + + // Pass up any other exceptions + throw apiEx; + } + } + + public async Task GetDataDumpEndpointAsync(string endpoint) + { + try + { + return await _api.GetDataDumpForEndpointAsync(endpoint); + } + catch (ApiException apiEx) + { + // Acquire new token and retry request (once) + if (IsInvalidTokenResponse(apiEx)) + { + await _tokenManager.RefreshTokenAsync(); + + return await _api.GetDataDumpForEndpointAsync(endpoint); + } + + // Pass up any other exceptions + throw apiEx; + } + } + /// /// Whether or not an ApiException represents an invalid_token response. /// diff --git a/IGDB/Models/DataDump.cs b/IGDB/Models/DataDump.cs new file mode 100644 index 0000000..9b6962c --- /dev/null +++ b/IGDB/Models/DataDump.cs @@ -0,0 +1,11 @@ +using System; + +namespace IGDB.Models +{ + public class DataDump + { + public string Endpoint { get; set; } + public string FileName { get; set; } + public DateTimeOffset UpdatedAt { get; set; } + } +} \ No newline at end of file diff --git a/IGDB/Models/DataDumpEndpoint.cs b/IGDB/Models/DataDumpEndpoint.cs new file mode 100644 index 0000000..731af74 --- /dev/null +++ b/IGDB/Models/DataDumpEndpoint.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; + +namespace IGDB.Models +{ + public class DataDumpEndpoint + { + public string S3Url { get; set; } + public string Endpoint { get; set; } + public string FileName { get; set; } + public long SizeBytes { get; set; } + public DateTimeOffset UpdatedAt { get; set; } + public string SchemaVersion { get; set; } + + /// + /// Dictionary representing the schema of the CSV file. Tied to SchemaVersion. + /// + /// + /// Example: + /// - id: "LONG" + /// - name: "STRING" + /// - created_at: "TIMESTAMP" + /// - franchises: "LONG[]" + /// - total_rating: "DOUBLE" + /// - total_rating_count: "INTEGER" + /// + public Dictionary Schema { get; set; } + } +} \ No newline at end of file