Skip to content

Commit

Permalink
fix: wait for release assets uploading
Browse files Browse the repository at this point in the history
  • Loading branch information
AlisaAkiron committed Jan 23, 2025
1 parent e0a86f1 commit 4ae9eeb
Show file tree
Hide file tree
Showing 7 changed files with 203 additions and 82 deletions.
18 changes: 18 additions & 0 deletions src/PallasBot.Application.Common/Models/GitHub/GitHubAsset.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System.Text.Json.Serialization;

namespace PallasBot.Application.Common.Models.GitHub;

public record GitHubAsset
{
[JsonPropertyName("id")]
public ulong Id { get; set; }

[JsonPropertyName("name")]
public string Name { get; set; } = string.Empty;

[JsonPropertyName("size")]
public ulong Size { get; set; }

[JsonPropertyName("browser_download_url")]
public string BrowserDownloadUrl { get; set; } = string.Empty;
}
30 changes: 30 additions & 0 deletions src/PallasBot.Application.Common/Models/GitHub/GitHubRelease.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using System.Text.Json.Serialization;

namespace PallasBot.Application.Common.Models.GitHub;

public record GitHubRelease
{
[JsonPropertyName("id")]
public ulong Id { get; set; }

[JsonPropertyName("url")]
public string Url { get; set; } = string.Empty;

[JsonPropertyName("html_url")]
public string HtmlUrl { get; set; } = string.Empty;

[JsonPropertyName("tag_name")]
public string TagName { get; set; } = string.Empty;

[JsonPropertyName("draft")]
public bool Draft { get; set; }

[JsonPropertyName("prerelease")]
public bool PreRelease { get; set; }

[JsonPropertyName("assets")]
public List<GitHubAsset> Assets { get; set; } = [];

[JsonPropertyName("body")]
public string Body { get; set; } = string.Empty;
}
16 changes: 16 additions & 0 deletions src/PallasBot.Application.Common/Services/GitHubApiService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,22 @@ public async Task<List<GitHubUser>> GetRepoContributorsAsync(string org, string

#endregion

#region Repository

public async Task<GitHubRelease> GetReleaseDetailAsync(string organization, string repository, ulong id, string? accessToken = null)
{
using var req = new GitHubHttpRequestBuilder()
.Get($"https://api.github.com/repos/{organization}/{repository}/releases/{id}")
.WithBearerAuth(accessToken)
.AcceptGitHubJson()
.WithLatestApiVersion()
.Build();

return await SendRequest<GitHubRelease>(req);
}

#endregion

private async Task<List<T>> GetPaginatedResponseAsync<T>(Func<GitHubHttpRequestBuilder> requestBuilder, string url)
{
var nextUrl = url;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,13 @@ public GitHubHttpRequestBuilder Post(string uri)
return this;
}

public GitHubHttpRequestBuilder WithBearerAuth(string token)
public GitHubHttpRequestBuilder WithBearerAuth(string? token)
{
if (string.IsNullOrEmpty(token))
{
return this;
}

_httpRequestMessage.Headers.Add("Authorization", $"Bearer {token}");
return this;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
using Discord;
using Discord.Rest;
using MassTransit;
using Microsoft.Extensions.Logging;
using PallasBot.Application.Common.Services;
using PallasBot.Application.Webhook.Models;
using PallasBot.Domain.Abstract;
using PallasBot.Domain.Constants;
using PallasBot.Domain.Enums;

namespace PallasBot.Application.Webhook.Consumers.GitHub;

public class MaaReleaseConsumer : IConsumer<MaaReleaseMqo>
{
private readonly GitHubApiService _gitHubApiService;
private readonly DiscordRestClient _discordRestClient;
private readonly IDynamicConfigurationService _dynamicConfigurationService;
private readonly ILogger<MaaReleaseConsumer> _logger;

public MaaReleaseConsumer(
GitHubApiService gitHubApiService,
DiscordRestClient discordRestClient,
IDynamicConfigurationService dynamicConfigurationService,
ILogger<MaaReleaseConsumer> logger)
{
_gitHubApiService = gitHubApiService;
_discordRestClient = discordRestClient;
_dynamicConfigurationService = dynamicConfigurationService;
_logger = logger;
}

public async Task Consume(ConsumeContext<MaaReleaseMqo> context)
{
var m = context.Message;

var channels = (await _dynamicConfigurationService
.GetAllAsync(DynamicConfigurationKey.MaaReleaseNotificationChannel))
.Select(x => ulong.TryParse(x.Value, out var v) ? v : (ulong?)null)
.Where(x => x != null)
.Select(x => x!.Value)
.ToList();
if (channels.Count == 0)
{
return;
}

var releaseAt = m.ReleaseAt;
var shouldCheckAt = releaseAt.AddMinutes(3);
var now = DateTimeOffset.UtcNow;
if (shouldCheckAt > now)
{
var diff = shouldCheckAt - now;
_logger.LogInformation("Waiting for {Timespan} to check release detail", diff);
await Task.Delay(diff);
}

var accessToken = await _gitHubApiService.GetGitHubAppAccessTokenAsync();
var release = await _gitHubApiService.GetReleaseDetailAsync(
MaaConstants.Organization, MaaConstants.MainRepository, m.ReleaseId, accessToken.Token);

var assetUrls = new Dictionary<string, string>();
var platforms = GetAssetPlatforms(release.TagName);
foreach (var asset in release.Assets)
{
if (string.IsNullOrEmpty(asset.Name) is false && platforms.TryGetValue(asset.Name, out var platform))
{
var sizeInMegabytes = (double)asset.Size / 1024 / 1024;
assetUrls.Add($"{platform} [{sizeInMegabytes:F1} MB]", asset.BrowserDownloadUrl);
}
}

var componentBuilder = new ComponentBuilder();
foreach (var (platform, url) in assetUrls.OrderByDescending(x => x.Value))
{
componentBuilder.WithButton(
label: platform,
style: ButtonStyle.Link,
url: url);
}

var downloadLinkMessage = assetUrls.Count == 0
? string.Empty
: $"\nOr, download MAA {release.TagName} for your platform by clicking the buttons below.";

var components = componentBuilder.Build();
var textMessage = $"""
## 🎉 New MAA Release: ** {release.TagName} **
Read the full release note [here]({release.HtmlUrl}).
Open or reopen your MAA client to get automatic updates.{downloadLinkMessage}
""";

foreach (var channelId in channels)
{
var channel = (IRestMessageChannel) await _discordRestClient.GetChannelAsync(channelId);

await channel.SendMessageAsync(
text: textMessage,
components: components);
}
}

private static Dictionary<string, string> GetAssetPlatforms(string name)
{
return new Dictionary<string, string>
{
[$"MAA-{name}-win-x64.zip"] = "Windows (x64)",
[$"MAA-{name}-macos-universal.dmg"] = "macOS (Universal, dmg)",
[$"MAA-{name}-linux-x86_64.tar.gz"] = "Linux (amd64, tar.gz)",
};
}
}
8 changes: 8 additions & 0 deletions src/PallasBot.Application.Webhook/Models/MaaReleaseMqo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace PallasBot.Application.Webhook.Models;

public record MaaReleaseMqo
{
public required ulong ReleaseId { get; set; }

public required DateTimeOffset ReleaseAt { get; set; }
}
Original file line number Diff line number Diff line change
@@ -1,29 +1,23 @@
using System.Diagnostics;
using System.Text.Json;
using Discord;
using Discord.Rest;
using MassTransit;
using PallasBot.Application.Common.Abstract;
using PallasBot.Application.Common.Models.Messages;
using PallasBot.Application.Webhook.Models;
using PallasBot.Application.Webhook.Services;
using PallasBot.Domain.Abstract;
using PallasBot.Domain.Enums;

namespace PallasBot.Application.Webhook.Processors;

public class GitHubWebhookProcessor : IWebhookProcessor
{
private readonly DiscordRestClient _discordRestClient;
private readonly IDynamicConfigurationService _dynamicConfigurationService;
private readonly GitHubWebhookValidator _gitHubWebhookValidator;
private readonly IPublishEndpoint _publishEndpoint;

public GitHubWebhookProcessor(
DiscordRestClient discordRestClient,
IDynamicConfigurationService dynamicConfigurationService,
GitHubWebhookValidator gitHubWebhookValidator)
GitHubWebhookValidator gitHubWebhookValidator, IPublishEndpoint publishEndpoint)
{
_discordRestClient = discordRestClient;
_dynamicConfigurationService = dynamicConfigurationService;
_gitHubWebhookValidator = gitHubWebhookValidator;
_publishEndpoint = publishEndpoint;
}

public async Task ProcessAsync(WebhookMessageMqo messageMqo)
Expand Down Expand Up @@ -56,13 +50,6 @@ public async Task ProcessAsync(WebhookMessageMqo messageMqo)

private async Task ProcessReleaseEventAsync(string body)
{
var channels = (await _dynamicConfigurationService
.GetAllAsync(DynamicConfigurationKey.MaaReleaseNotificationChannel))
.Select(x => ulong.TryParse(x.Value, out var v) ? v : (ulong?)null)
.Where(x => x != null)
.Select(x => x!.Value)
.ToList();

using var doc = JsonDocument.Parse(body);
var root = doc.RootElement;

Expand All @@ -74,69 +61,12 @@ private async Task ProcessReleaseEventAsync(string body)

var release = root.GetProperty("release");

var name = release.GetProperty("name").GetString()!;
var htmlUrl = release.GetProperty("html_url").GetString()!;

var assets = release.GetProperty("assets")
.EnumerateArray()
.ToArray();

var assetUrls = new Dictionary<string, string>();
var platforms = GetAssetPlatforms(name);
foreach (var asset in assets)
{
var assetName = asset.GetProperty("name").GetString();
if (string.IsNullOrEmpty(assetName) is false && platforms.TryGetValue(assetName, out var platform))
{
var downloadUrl = asset.GetProperty("browser_download_url").GetString();
var size = asset.GetProperty("size").GetDouble();

var sizeInMegabytes = size / 1024 / 1024;

if (string.IsNullOrEmpty(downloadUrl) is false)
{
assetUrls.Add($"{platform} [{sizeInMegabytes:F1} MB]", downloadUrl);
}
}
}

var componentBuilder = new ComponentBuilder();
foreach (var (platform, url) in assetUrls.OrderByDescending(x => x.Value))
{
componentBuilder.WithButton(
label: platform,
style: ButtonStyle.Link,
url: url);
}

var components = componentBuilder.Build();
var textMessage = $"""
## 🎉 New MAA Release: ** {name} **
Read the full release note [here]({htmlUrl}).
Open or reopen your MAA client to get automatic updates.
Or, download MAA {name} for your platform by clicking the buttons below.
""";

foreach (var channelId in channels)
{
var channel = (IRestMessageChannel) await _discordRestClient.GetChannelAsync(channelId);

await channel.SendMessageAsync(
text: textMessage,
components: components);
}
}

private static Dictionary<string, string> GetAssetPlatforms(string name)
{
return new Dictionary<string, string>
var id = release.GetProperty("id").GetUInt64();
var publishedAt = release.GetProperty("published_at").GetDateTimeOffset();
await _publishEndpoint.Publish(new MaaReleaseMqo
{
[$"MAA-{name}-win-x64.zip"] = "Windows (x64)",
[$"MAA-{name}-macos-universal.dmg"] = "macOS (Universal, dmg)",
[$"MAA-{name}-linux-x86_64.tar.gz"] = "Linux (amd64, tar.gz)",
};
ReleaseId = id,
ReleaseAt = publishedAt
});
}
}

0 comments on commit 4ae9eeb

Please sign in to comment.