Skip to content

Commit

Permalink
Merge pull request #2158 from andy840119/wrap-changelog-request-into-…
Browse files Browse the repository at this point in the history
…request-object

Wrap changelog request into request object.
  • Loading branch information
andy840119 authored Dec 21, 2023
2 parents 21e84f6 + 379a748 commit 0f6cfa3
Show file tree
Hide file tree
Showing 13 changed files with 338 additions and 140 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,11 @@ public partial class TestSceneKaraokeChangeLogMarkdownContainer : OsuTestScene
[SetUp]
public void SetUp() => Schedule(() =>
{
var build = new APIChangelogBuild("karaoke-dev", "karaoke-dev.github.io")
var build = new APIChangelogBuild
{
Path = "content/changelog/2020.0620",
DocumentUrl = "https://raw.githubusercontent.com/karaoke-dev/karaoke-dev.github.io/master/content/changelog/2020.0620",
RootUrl = "https://github.com/karaoke-dev/karaoke-dev.github.io/tree/master/content/changelog/2020.0620",
Content = "---\ntitle: \"2020.0620\"\ndate: 2020-06-20\n---\n\n## Achievement\n\n- Might support convert `UTAU`/`SynthV` project into karaoke beatmap in future. [karaoke](#100#101@andy840119)",
};

Children = new Drawable[]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright (c) andy840119 <[email protected]>. Licensed under the GPL Licence.
// See the LICENCE file in the repository root for full licence text.

using System.Threading.Tasks;
using Octokit;
using osu.Game.Rulesets.Karaoke.Online.API.Requests.Responses;

namespace osu.Game.Rulesets.Karaoke.Online.API.Requests;

public class GetChangelogBuildRequest : GithubChangeLogAPIRequest<APIChangelogBuild>
{
private readonly APIChangelogBuild originBuild;

public GetChangelogBuildRequest(APIChangelogBuild originBuild)
{
this.originBuild = originBuild;
}

protected override async Task<APIChangelogBuild> Perform(IGitHubClient client)
{
string contentString = await GetChangelogContent(client, originBuild.Version).ConfigureAwait(false);
return CreateBuildWithContent(originBuild, contentString);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// Copyright (c) andy840119 <[email protected]>. Licensed under the GPL Licence.
// See the LICENCE file in the repository root for full licence text.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Octokit;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Game.Rulesets.Karaoke.Extensions;
using osu.Game.Rulesets.Karaoke.Online.API.Requests.Responses;

namespace osu.Game.Rulesets.Karaoke.Online.API.Requests;

public class GetChangelogRequest : GithubChangeLogAPIRequest<APIChangelogIndex>
{
protected override async Task<APIChangelogIndex> Perform(IGitHubClient client)
{
var builds = await getAllBuilds(client).ConfigureAwait(false);
var previewBuilds = (await Task.WhenAll(builds.Take(5).Select(x => createPreviewBuild(client, x))).ConfigureAwait(false)).ToList();
int[] years = generateYears(builds);

return new APIChangelogIndex
{
Years = years,
Builds = builds,
PreviewBuilds = previewBuilds,
};
}

private static async Task<List<APIChangelogBuild>> getAllBuilds(IGitHubClient client)
{
var reposAscending = await client
.Repository
.Content
.GetAllContents(ORGANIZATION_NAME, PROJECT_NAME, CHANGELOG_PATH)
.ConfigureAwait(false);

var builds = reposAscending
.Reverse()
.Where(x => x.Type == ContentType.Dir)
.Select(createBuild)
.ToList();

// adjust the mapping of previous/next versions by hand.
foreach (var build in builds)
{
build.Versions.Previous = builds.GetPrevious(build);
build.Versions.Next = builds.GetNext(build);
}

return builds;
}

private static APIChangelogBuild createBuild(RepositoryContent content)
{
return new APIChangelogBuild
{
DocumentUrl = getDocumentUrl(content.Path),
RootUrl = content.HtmlUrl,
Version = content.Name,
PublishedAt = getPublishDateFromName(content.Name),
};

static DateTimeOffset getPublishDateFromName(string name)
{
var regex = new Regex("(?<year>[-0-9]+).(?<month>[-0-9]{2})(?<day>[-0-9]{2})");
var result = regex.Match(name);
if (!result.Success)
return DateTimeOffset.MaxValue;

int year = result.GetGroupValue<int>("year");
int month = result.GetGroupValue<int>("month");
int day = result.GetGroupValue<int>("day");

return new DateTimeOffset(new DateTime(year, month, day));
}

string getDocumentUrl(string path)
=> $"https://raw.githubusercontent.com/{ORGANIZATION_NAME}/{PROJECT_NAME}/{BRANCH_NAME}/{path}/";
}

private static async Task<APIChangelogBuild> createPreviewBuild(IGitHubClient client, APIChangelogBuild originBuild)
{
string contentString = await GetChangelogContent(client, originBuild.Version).ConfigureAwait(false);
return CreateBuildWithContent(originBuild, contentString);
}

private static int[] generateYears(IEnumerable<APIChangelogBuild> builds)
=> builds.Select(x => x.PublishedAt.Year).Distinct().ToArray();
}
84 changes: 84 additions & 0 deletions osu.Game.Rulesets.Karaoke/Online/API/Requests/GithubAPIRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// Copyright (c) andy840119 <[email protected]>. Licensed under the GPL Licence.
// See the LICENCE file in the repository root for full licence text.

using System;
using System.Threading.Tasks;
using Octokit;
using osu.Game.Online.API;

namespace osu.Game.Rulesets.Karaoke.Online.API.Requests;

public abstract class GithubAPIRequest<T> where T : class
{
protected virtual GitHubClient CreateGitHubClient() => new(new ProductHeaderValue(organizationName));

/// <summary>
/// Invoked on successful completion of an API request.
/// This will be scheduled to the API's internal scheduler (run on update thread automatically).
/// </summary>
public event APISuccessHandler<T>? Success;

/// <summary>
/// Invoked on failure to complete an API request.
/// This will be scheduled to the API's internal scheduler (run on update thread automatically).
/// </summary>
public event APIFailureHandler? Failure;

private readonly object completionStateLock = new();

/// <summary>
/// The state of this request, from an outside perspective.
/// This is used to ensure correct notification events are fired.
/// </summary>
public APIRequestCompletionState CompletionState { get; private set; }

private readonly string organizationName;

protected GithubAPIRequest(string organizationName)
{
this.organizationName = organizationName;
}

public async Task Perform()
{
var client = CreateGitHubClient();

try
{
var response = await Perform(client).ConfigureAwait(false);
triggerSuccess(response);
}
catch (Exception e)
{
triggerFailure(e);
}
}

protected abstract Task<T> Perform(IGitHubClient client);

private void triggerSuccess(T response)
{
lock (completionStateLock)
{
if (CompletionState != APIRequestCompletionState.Waiting)
return;

CompletionState = APIRequestCompletionState.Completed;
}

Success?.Invoke(response);
}

private void triggerFailure(Exception e)
{
lock (completionStateLock)
{
if (CompletionState != APIRequestCompletionState.Waiting)
return;

CompletionState = APIRequestCompletionState.Failed;
}

Failure?.Invoke(e);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright (c) andy840119 <[email protected]>. Licensed under the GPL Licence.
// See the LICENCE file in the repository root for full licence text.

using System.Threading.Tasks;
using Octokit;
using osu.Game.Rulesets.Karaoke.Online.API.Requests.Responses;

namespace osu.Game.Rulesets.Karaoke.Online.API.Requests;

public abstract class GithubChangeLogAPIRequest<T> : GithubAPIRequest<T> where T : class
{
protected const string ORGANIZATION_NAME = "karaoke-dev";
protected const string PROJECT_NAME = $"{ORGANIZATION_NAME}.github.io";
protected const string BRANCH_NAME = "master";
protected const string CHANGELOG_PATH = "content/changelog";

protected GithubChangeLogAPIRequest()
: base(ORGANIZATION_NAME)
{
}

protected static async Task<string> GetChangelogContent(IGitHubClient client, string version)
{
string changeLogPath = $"{CHANGELOG_PATH}/{version}/index.md";
byte[]? content = await client
.Repository
.Content
.GetRawContent(ORGANIZATION_NAME, PROJECT_NAME, changeLogPath)
.ConfigureAwait(false);

// convert the content to a string
return System.Text.Encoding.UTF8.GetString(content);
}

protected static APIChangelogBuild CreateBuildWithContent(APIChangelogBuild originBuild, string content)
{
return new APIChangelogBuild
{
DocumentUrl = originBuild.DocumentUrl,
RootUrl = originBuild.RootUrl,
Version = originBuild.Version,
Content = content,
Versions =
{
Previous = originBuild.Versions.Previous,
Next = originBuild.Versions.Next,
},
PublishedAt = originBuild.PublishedAt,
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,64 +7,38 @@ namespace osu.Game.Rulesets.Karaoke.Online.API.Requests.Responses;

public class APIChangelogBuild
{
/// <summary>
///
/// </summary>
/// <param name="organization">Account or organization name</param>
/// <param name="project">Project name</param>
/// <param name="branch">Branch name</param>
public APIChangelogBuild(string organization, string project, string branch = "master")
{
OrganizationName = organization;
ProjectName = project;
Branch = branch;
Versions = new VersionNavigation();
}

/// <summary>
/// Organization name
/// </summary>
public string OrganizationName { get; }

/// <summary>
/// Project name
/// </summary>
public string ProjectName { get; }

/// <summary>
/// Branch name
/// </summary>
public string Branch { get; }

/// <summary>
/// The URL of the loaded document.
/// </summary>
public string DocumentUrl => $"https://raw.githubusercontent.com/{OrganizationName}/{ProjectName}/{Branch}/{Path}/";
public string DocumentUrl { get; set; } = null!;

/// <summary>
/// The base URL for all root-relative links.
/// </summary>
public string RootUrl { get; set; } = null!;

/// <summary>
/// Path of the project
/// Version number
/// </summary>
public string Path { get; set; } = null!;
/// <example>2023.0123</example>
/// <example>2023.1111</example>
public string Version { get; set; } = null!;

/// <summary>
/// Path to download readme url
/// Display version
/// </summary>
public string ReadmeDownloadUrl => $"{DocumentUrl}index.md";
public string DisplayVersion => Version;

/// <summary>
/// Display version
/// Might be preview or detail markdown content.
/// And the content is markdown format.
/// </summary>
public string DisplayVersion { get; set; } = null!;
public string? Content { get; set; }

/// <summary>
/// Version
/// </summary>
public VersionNavigation Versions { get; }
public VersionNavigation Versions { get; } = new();

/// <summary>
/// Created date.
Expand All @@ -83,4 +57,6 @@ public class VersionNavigation
/// </summary>
public APIChangelogBuild? Previous { get; set; }
}

public override string ToString() => $"Karaoke! {DisplayVersion}";
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@

namespace osu.Game.Rulesets.Karaoke.Online.API.Requests.Responses;

public class APIChangelogSidebar
public class APIChangelogIndex
{
public IEnumerable<APIChangelogBuild> Changelogs { get; set; } = Array.Empty<APIChangelogBuild>();
public List<APIChangelogBuild> Builds { get; set; } = new();

public List<APIChangelogBuild> PreviewBuilds { get; set; } = new();

public int[] Years { get; set; } = Array.Empty<int>();
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text.RegularExpressions;
using Markdig.Syntax.Inlines;
using osu.Framework.Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Layout;
Expand All @@ -25,17 +23,7 @@ public ChangeLogMarkdownContainer(APIChangelogBuild build)
{
DocumentUrl = build.DocumentUrl;
RootUrl = build.RootUrl;

using var httpClient = new HttpClient();

try
{
Text = httpClient.GetStringAsync(build.ReadmeDownloadUrl).GetResultSafely();
}
catch (Exception)
{
Text = "Oops, seems there's something wrong with network.";
}
Text = build.Content;
}

public override OsuMarkdownTextFlowContainer CreateTextFlow() => new ChangeLogMarkdownTextFlowContainer();
Expand Down
Loading

0 comments on commit 0f6cfa3

Please sign in to comment.