Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions magos-modificus/config/IntegrationsConfig.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
namespace Magos.Modificus.Config;

/// <summary>
/// External-service integration settings (mod sources). Bound from the
/// <c>Integrations</c> section of <see cref="MagosConfig"/> by the config loader
/// in <c>Magos.Modificus.General</c>. Every field carries a default so an absent
/// section yields a usable object.
/// </summary>
public sealed class IntegrationsConfig
{
/// <summary>GitHub Releases client settings.</summary>
public GitHubConfig GitHub { get; set; } = new();
}

/// <summary>
/// GitHub Releases client settings. The base URL defaults to the public GitHub
/// REST API; an optional personal access token raises the rate limit / unlocks
/// private repos (Phase 1: no token-management UI — supply via config only).
/// </summary>
public sealed class GitHubConfig
{
/// <summary>
/// The GitHub REST API root, without a trailing slash. Defaults to the
/// public endpoint; override for GitHub Enterprise (<c>https://&lt;host&gt;/api/v3</c>).
/// </summary>
public string BaseUrl { get; set; } = "https://api.github.com";

/// <summary>
/// An optional personal access token sent as a <c>Bearer</c> token. When
/// unset, requests are anonymous (public releases need no auth).
/// </summary>
public string? Token { get; set; }
}
3 changes: 3 additions & 0 deletions magos-modificus/config/MagosConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ public sealed class MagosConfig
/// </summary>
public string EnginseerRuntimeDir { get; set; } = AppPaths.DefaultEnginseerRuntimeDir;

/// <summary>External-service (mod-source) integration settings.</summary>
public IntegrationsConfig Integrations { get; set; } = new();

/// <summary>A fully-defaulted config instance.</summary>
public static MagosConfig CreateDefault() => new();
}
50 changes: 50 additions & 0 deletions magos-modificus/integrations/GitHubApiException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
namespace Magos.Modificus.Integrations;

/// <summary>
/// Thrown when the GitHub REST API returns a non-success response (other than
/// the <c>404</c> cases the client maps to <c>null</c> / empty). Carries the
/// HTTP status and the API's <c>message</c> field when available.
/// </summary>
/// <remarks>
/// Unsealed so <see cref="GitHubRateLimitException"/> can specialize it; callers
/// can catch the base type to handle every GitHub API failure uniformly.
/// </remarks>
public class GitHubApiException : Exception
{
/// <summary>The HTTP status code returned by the API.</summary>
public int StatusCode { get; }

/// <param name="statusCode">The HTTP status code.</param>
/// <param name="message">The API error message (its <c>message</c> field when available).</param>
public GitHubApiException(int statusCode, string message)
: base(message)
{
StatusCode = statusCode;
}
}

/// <summary>
/// Thrown when the GitHub API refuses a request because the rate limit is
/// exhausted — detected via a <c>403</c>/<c>429</c> status carrying
/// <c>X-RateLimit-Remaining: 0</c>. Carries the reset time
/// (<c>X-RateLimit-Reset</c>) when GitHub reports it, so callers can advise the
/// user when to retry. <see cref="GitHubApiException.StatusCode"/> reflects the
/// actual response status (403 or 429).
/// </summary>
public sealed class GitHubRateLimitException : GitHubApiException
{
/// <summary>
/// When the rate window resets (from <c>X-RateLimit-Reset</c>), or
/// <c>null</c> if the header was absent.
/// </summary>
public DateTimeOffset? ResetAt { get; }

internal GitHubRateLimitException(int statusCode, DateTimeOffset? resetAt)
: base(
statusCode,
"GitHub API rate limit exhausted (HTTP " + statusCode + ")"
+ (resetAt.HasValue ? $" — resets at {resetAt:O}." : "."))
{
ResetAt = resetAt;
}
}
Loading
Loading