Skip to content
Merged
29 changes: 9 additions & 20 deletions .github/workflows/dotnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,17 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v5
- name: Setup .NET
uses: actions/setup-dotnet@v3
uses: actions/setup-dotnet@v5
with:
dotnet-version: 7.0.x
dotnet-version: '10.0.x'

- name: Check Tag
id: check-tag
run: |
if [[ v${{ github.event.ref }} =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo ::set-output name=match::true
echo "match=true" >> $GITHUB_OUTPUT
fi

- name: Run Unit Tests
Expand All @@ -39,24 +39,13 @@ jobs:
dotnet build -c Release
dotnet pack -c Release -o /tmp/nupkgs -v m -p:IncludeSymbols=true -p:SymbolPackageFormat=snupkg
dotnet nuget push /tmp/nupkgs/NosCore.ParserInputGenerator.${{github.event.ref}}.nupkg -s https://api.nuget.org/v3/index.json -k ${{secrets.NUGET_API_KEY}}
echo ::set-output name=ARTIFACT_PATH::/tmp/nupkgs/NosCore.ParserInputGenerator.${{github.event.ref}}.snupkg
echo ::set-output name=ARTIFACT_NAME::NosCore.ParserInputGenerator.${{github.event.ref}}.snupkg

- name: Gets Latest Release
if: steps.check-tag.outputs.match == 'true'
id: latest_release_info
uses: jossef/action-latest-release-info@v1.1.0
env:
GITHUB_TOKEN: ${{ secrets.REPO_TOKEN }}
echo "ARTIFACT_PATH=/tmp/nupkgs/NosCore.ParserInputGenerator.${{github.event.ref}}.snupkg" >> $GITHUB_OUTPUT
echo "ARTIFACT_NAME=NosCore.ParserInputGenerator.${{github.event.ref}}.snupkg" >> $GITHUB_OUTPUT

- name: Upload Release Asset
if: steps.check-tag.outputs.match == 'true'
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.REPO_TOKEN }}
uses: softprops/action-gh-release@v2
with:
upload_url: ${{ steps.latest_release_info.outputs.upload_url }}
asset_path: ${{ steps.build_artifact.outputs.ARTIFACT_PATH }}
asset_name: ${{ steps.build_artifact.outputs.ARTIFACT_NAME }}
asset_content_type: application/zip
files: ${{ steps.build_artifact.outputs.ARTIFACT_PATH }}
token: ${{ secrets.REPO_TOKEN }}

Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

namespace NosCore.ParserInputGenerator.Launcher.Configuration
{
/// <summary>
/// Configuration for the Parser Input Generator.
/// </summary>
public class ParserInputGeneratorConfiguration : LanguageConfiguration
{
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,19 @@

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<OutputPath>..\..\build\</OutputPath>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.2.1" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.2.1" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\NosCore.ParserInputGenerator\NosCore.ParserInputGenerator.csproj" />
</ItemGroup>
Expand Down
14 changes: 13 additions & 1 deletion src/NosCore.ParserInputGenerator.Launcher/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,25 @@

namespace NosCore.ParserInputGenerator.Launcher
{
class Program
/// <summary>
/// Main program entry point for the Parser Input Generator launcher.
/// </summary>
public class Program
{
/// <summary>
/// Application entry point.
/// </summary>
/// <param name="args">Command line arguments.</param>
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}

/// <summary>
/// Creates and configures the host builder.
/// </summary>
/// <param name="args">Command line arguments.</param>
/// <returns>The configured host builder.</returns>
public static IHostBuilder CreateHostBuilder(string[] args)
{
var configuration = new ParserInputGeneratorConfiguration();
Expand Down
14 changes: 14 additions & 0 deletions src/NosCore.ParserInputGenerator.Launcher/Worker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@

namespace NosCore.ParserInputGenerator.Launcher
{
/// <summary>
/// Background service worker that downloads and processes parser input files.
/// </summary>
public class Worker : BackgroundService
{
private const string ConsoleText = "PARSER INPUT GENERATOR - NosCoreIO";
Expand Down Expand Up @@ -45,13 +48,24 @@ public class Worker : BackgroundService
"NSgtdData.NOS"
};

/// <summary>
/// Initializes a new instance of the <see cref="Worker"/> class.
/// </summary>
/// <param name="logger">The logger instance.</param>
/// <param name="client">The client downloader.</param>
/// <param name="extractor">The file extractor.</param>
public Worker(ILogger<Worker> logger, IClientDownloader client, IExtractor extractor)
{
_logger = logger;
_client = client;
_extractor = extractor;
}

/// <summary>
/// Executes the worker task to download, extract, and package parser input files.
/// </summary>
/// <param name="stoppingToken">Cancellation token to stop the service.</param>
/// <returns>A task representing the asynchronous operation.</returns>
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
try
Expand Down
12 changes: 12 additions & 0 deletions src/NosCore.ParserInputGenerator/Downloader/ClientDownloader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,29 @@

namespace NosCore.ParserInputGenerator.Downloader
{
/// <summary>
/// Implements client file downloading functionality.
/// </summary>
public class ClientDownloader : IClientDownloader
{
private readonly IHttpClientFactory _clientFactory;
private readonly ILogger<ClientDownloader> _logger;

/// <summary>
/// Initializes a new instance of the <see cref="ClientDownloader"/> class.
/// </summary>
/// <param name="clientFactory">The HTTP client factory.</param>
/// <param name="logger">The logger instance.</param>
public ClientDownloader(IHttpClientFactory clientFactory, ILogger<ClientDownloader> logger)
{
_clientFactory = clientFactory;
_logger = logger;
}

/// <inheritdoc/>
public Task<ClientManifest> DownloadManifest() => DownloadManifestAsync(RegionType.EN);

/// <inheritdoc/>
public async Task<ClientManifest> DownloadManifestAsync(RegionType region)
{
var client = _clientFactory.CreateClient();
Expand All @@ -42,8 +52,10 @@ public async Task<ClientManifest> DownloadManifestAsync(RegionType region)
}) ?? throw new InvalidOperationException();
}

/// <inheritdoc/>
public async Task DownloadClientAsync() => await DownloadClientAsync(await DownloadManifest());

/// <inheritdoc/>
public async Task DownloadClientAsync(ClientManifest manifest)
{
async Task Download(Entry entry)
Expand Down
33 changes: 33 additions & 0 deletions src/NosCore.ParserInputGenerator/Downloader/ClientManifest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,68 @@

namespace NosCore.ParserInputGenerator.Downloader
{
/// <summary>
/// Represents a client manifest containing file entries and metadata.
/// </summary>
public class ClientManifest
{
/// <summary>
/// Gets or sets the array of file entries in the manifest.
/// </summary>
[JsonPropertyName("entries")]
public Entry[] Entries { get; set; } = null!;

/// <summary>
/// Gets or sets the total size of all files in bytes.
/// </summary>
[JsonPropertyName("totalSize")]
public long TotalSize { get; set; }

/// <summary>
/// Gets or sets the build number of the client.
/// </summary>
[JsonPropertyName("build")]
public long Build { get; set; }
}

/// <summary>
/// Represents an individual file entry in the client manifest.
/// </summary>
public class Entry
{
/// <summary>
/// Gets or sets the file path.
/// </summary>
[JsonPropertyName("path")]
public string? Path { get; set; }

/// <summary>
/// Gets or sets the SHA1 hash of the file.
/// </summary>
[JsonPropertyName("sha1")]
public string? Sha1 { get; set; }

/// <summary>
/// Gets or sets the file name.
/// </summary>
[JsonPropertyName("file")]
public string File { get; set; } = null!;

/// <summary>
/// Gets or sets file flags.
/// </summary>
[JsonPropertyName("flags")]
public long Flags { get; set; }

/// <summary>
/// Gets or sets the file size in bytes.
/// </summary>
[JsonPropertyName("size")]
public long Size { get; set; }

/// <summary>
/// Gets or sets a value indicating whether this entry is a folder.
/// </summary>
[JsonPropertyName("folder")]
public bool Folder { get; set; }
}
Expand Down
23 changes: 23 additions & 0 deletions src/NosCore.ParserInputGenerator/Downloader/IClientDownloader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,35 @@

namespace NosCore.ParserInputGenerator.Downloader
{
/// <summary>
/// Interface for downloading client files and manifests.
/// </summary>
public interface IClientDownloader
{
/// <summary>
/// Downloads the client manifest using the default region.
/// </summary>
/// <returns>The downloaded client manifest.</returns>
Task<ClientManifest> DownloadManifest();

/// <summary>
/// Downloads the client manifest for a specific region.
/// </summary>
/// <param name="region">The region to download from.</param>
/// <returns>The downloaded client manifest.</returns>
Task<ClientManifest> DownloadManifestAsync(RegionType region);

/// <summary>
/// Downloads the client files using the default manifest.
/// </summary>
/// <returns>A task representing the asynchronous operation.</returns>
Task DownloadClientAsync();

/// <summary>
/// Downloads the client files specified in the manifest.
/// </summary>
/// <param name="manifest">The manifest containing file information.</param>
/// <returns>A task representing the asynchronous operation.</returns>
Task DownloadClientAsync(ClientManifest manifest);
}
}
10 changes: 10 additions & 0 deletions src/NosCore.ParserInputGenerator/Extractor/Extractor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,29 @@

namespace NosCore.ParserInputGenerator.Extractor
{
/// <summary>
/// Implements file extraction functionality for NostaleData archives.
/// </summary>
public class Extractor : IExtractor
{
private readonly ILogger<Extractor> _logger;

/// <summary>
/// Initializes a new instance of the <see cref="Extractor"/> class.
/// </summary>
/// <param name="logger">The logger instance.</param>
public Extractor(ILogger<Extractor> logger)
{
_logger = logger;
}

/// <inheritdoc/>
public Task ExtractAsync(FileInfo file, string dest) => ExtractAsync(file, dest, false);

/// <inheritdoc/>
public Task ExtractAsync(FileInfo file) => ExtractAsync(file, $".{Path.DirectorySeparatorChar}output{Path.DirectorySeparatorChar}");

/// <inheritdoc/>
public async Task ExtractAsync(FileInfo nosFile, string directory, bool rename)
{
async Task WriteFile(string fileName, MemoryStream decryptedContent)
Expand Down
23 changes: 23 additions & 0 deletions src/NosCore.ParserInputGenerator/Extractor/IExtractor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,33 @@

namespace NosCore.ParserInputGenerator.Extractor
{
/// <summary>
/// Interface for extracting archived files.
/// </summary>
public interface IExtractor
{
/// <summary>
/// Extracts a file to the default directory.
/// </summary>
/// <param name="file">The file to extract.</param>
/// <returns>A task representing the asynchronous operation.</returns>
Task ExtractAsync(FileInfo file);

/// <summary>
/// Extracts a file to a specified directory.
/// </summary>
/// <param name="file">The file to extract.</param>
/// <param name="directory">The target directory.</param>
/// <returns>A task representing the asynchronous operation.</returns>
Task ExtractAsync(FileInfo file, string directory);

/// <summary>
/// Extracts a file to a specified directory with optional renaming.
/// </summary>
/// <param name="file">The file to extract.</param>
/// <param name="directory">The target directory.</param>
/// <param name="rename">Whether to rename extracted files.</param>
/// <returns>A task representing the asynchronous operation.</returns>
Task ExtractAsync(FileInfo file, string directory, bool rename);
}
}
20 changes: 20 additions & 0 deletions src/NosCore.ParserInputGenerator/I18N/LogLanguage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@

namespace NosCore.ParserInputGenerator.I18N
{
/// <summary>
/// Provides localized log messages based on language keys.
/// </summary>
public sealed class LogLanguage
{
private static LogLanguage? _instance;
Expand All @@ -26,15 +29,32 @@ private LogLanguage()
assem);
}

/// <summary>
/// Gets or sets the language/region type for localization.
/// </summary>
public static RegionType Language { get; set; }

/// <summary>
/// Gets the singleton instance of LogLanguage.
/// </summary>
public static LogLanguage Instance => _instance ??= new LogLanguage();

/// <summary>
/// Gets a localized message from the specified key using the default culture.
/// </summary>
/// <param name="messageKey">The message key to retrieve.</param>
/// <returns>The localized message string.</returns>
public string GetMessageFromKey(LogLanguageKey messageKey)
{
return GetMessageFromKey(messageKey, null);
}

/// <summary>
/// Gets a localized message from the specified key using a specific culture.
/// </summary>
/// <param name="messageKey">The message key to retrieve.</param>
/// <param name="culture">The culture name to use, or null for default.</param>
/// <returns>The localized message string.</returns>
public string GetMessageFromKey(LogLanguageKey messageKey, string? culture)
{
var cult = culture != null ? new CultureInfo(culture) : ResourceCulture;
Expand Down
Loading