Skip to content

Commit add1bd3

Browse files
authored
Merge pull request #136 from AlamoEngine-Tools/develop
support null for name resolver and more relaxed logging.
2 parents d8b544e + 874a67c commit add1bd3

11 files changed

Lines changed: 64 additions & 81 deletions

File tree

src/PetroGlyph.Games.EawFoc.Clients/src/Arguments/ArgumentValidityStatus.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
namespace PG.StarWarsGame.Infrastructure.Clients.Arguments;
22

33
/// <summary>
4-
/// Indicates the validity of a <see cref="IGameArgument"/>
4+
/// Indicates the validity of a <see cref="IGameArgument"/>.
55
/// </summary>
66
public enum ArgumentValidityStatus
77
{

src/PetroGlyph.Games.EawFoc/src/Services/GameFactory.cs

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,11 @@
88

99
namespace PG.StarWarsGame.Infrastructure.Services;
1010

11-
/// <inheritdoc/>
12-
internal sealed class GameFactory : IGameFactory
11+
internal sealed class GameFactory(IServiceProvider serviceProvider) : IGameFactory
1312
{
14-
private readonly IGameNameResolver _nameResolver;
15-
private readonly IServiceProvider _serviceProvider;
13+
private readonly IGameNameResolver _nameResolver = serviceProvider.GetRequiredService<IGameNameResolver>();
14+
private readonly IServiceProvider _serviceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider));
1615

17-
/// <summary>
18-
/// Creates a new factory instances. Uses <see cref="EnglishGameNameResolver"/> for the game's name resolution.
19-
/// </summary>
20-
/// <param name="serviceProvider">The service provider which gets passed to the game instances.</param>
21-
public GameFactory(IServiceProvider serviceProvider)
22-
{
23-
_serviceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider));
24-
_nameResolver = serviceProvider.GetRequiredService<IGameNameResolver>();
25-
}
26-
2716
/// <inheritdoc/>
2817
public IGame CreateGame(GameDetectionResult gameDetection, CultureInfo culture)
2918
{
@@ -45,7 +34,10 @@ public IGame CreateGame(IGameIdentity identity, IDirectoryInfo location, bool ch
4534
throw new ArgumentException("Cannot create a game with undefined platform");
4635

4736
var name = _nameResolver.ResolveName(identity, culture);
48-
var game = new PetroglyphStarWarsGame(identity, location, name, _serviceProvider);
37+
if (string.IsNullOrEmpty(name))
38+
throw new GameException("Cannot create game with null or empty name.");
39+
40+
var game = new PetroglyphStarWarsGame(identity, location, name!, _serviceProvider);
4941
if (checkGameExists && !game.Exists())
5042
throw new GameException($"Game does not exists at location: {location}");
5143

src/PetroGlyph.Games.EawFoc/src/Services/Name/Games/EnglishGameNameResolver.cs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,20 @@ namespace PG.StarWarsGame.Infrastructure.Services.Name;
99
/// </summary>
1010
public sealed class EnglishGameNameResolver : IGameNameResolver
1111
{
12+
/// <summary>
13+
/// Returns the english name of the game, regardless of the given <paramref name="culture"/>
14+
/// </summary>
15+
public string ResolveName(IGameIdentity game, CultureInfo culture)
16+
{
17+
return ResolveName(game);
18+
}
19+
1220
/// <summary>
1321
/// Returns the english name of the game.
1422
/// </summary>
15-
public string ResolveName(IGameIdentity game)
23+
private string ResolveName(IGameIdentity game)
1624
{
17-
if (game == null)
25+
if (game == null)
1826
throw new ArgumentNullException(nameof(game));
1927
var gameName = game.Type == GameType.Eaw
2028
? PetroglyphStarWarsGameConstants.EmpireAtWarEnglishNameShort
@@ -23,11 +31,4 @@ public string ResolveName(IGameIdentity game)
2331
return $"{gameName} ({platform})";
2432
}
2533

26-
/// <summary>
27-
/// Returns the english name of the game, regardless of the given <paramref name="culture"/>
28-
/// </summary>
29-
public string ResolveName(IGameIdentity game, CultureInfo culture)
30-
{
31-
return ResolveName(game);
32-
}
3334
}

src/PetroGlyph.Games.EawFoc/src/Services/Name/Games/IGameNameResolver.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,5 @@ public interface IGameNameResolver
1414
/// <param name="game">The game which name shall get resolved.</param>
1515
/// <param name="culture">The culture context.</param>
1616
/// <returns>The resolved name.</returns>
17-
string ResolveName(IGameIdentity game, CultureInfo culture);
17+
string? ResolveName(IGameIdentity game, CultureInfo culture);
1818
}

src/PetroGlyph.Games.EawFoc/src/Services/Name/Mods/CompositeModNameResolver.cs

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,36 +4,36 @@
44
using EawModinfo.Spec;
55
using Microsoft.Extensions.DependencyInjection;
66
using Microsoft.Extensions.Logging;
7-
using PG.StarWarsGame.Infrastructure.Mods;
87

98
namespace PG.StarWarsGame.Infrastructure.Services.Name;
109

1110
/// <summary>
12-
/// <see cref="IModNameResolver"/> which takes a sorted list of <see cref="IModNameResolver"/> and returns the first valid result.
11+
/// <see cref="IModNameResolver"/> which takes a sorted list of <see cref="IModNameResolver"/> and returns the first non-null or non-empty result.
1312
/// </summary>
1413
public sealed class CompositeModNameResolver : IModNameResolver
1514
{
1615
private readonly IList<IModNameResolver> _resolvers;
1716
private readonly ILogger? _logger;
1817

1918
/// <summary>
20-
/// Create a new instance.
19+
/// Initializes a new instance of the <see cref="CompositeModNameResolver"/> class with a factory method for subsequent resolvers.
2120
/// </summary>
2221
/// <param name="serviceProvider">The service provider.</param>
2322
/// <param name="resolverFactory">Factory method to create a list of <see cref="IModNameResolver"/>.</param>
2423
public CompositeModNameResolver(IServiceProvider serviceProvider, Func<IServiceProvider, IList<IModNameResolver>> resolverFactory)
2524
{
2625
if (serviceProvider == null)
2726
throw new ArgumentNullException(nameof(serviceProvider));
28-
if (resolverFactory == null) throw new ArgumentNullException(nameof(resolverFactory));
27+
if (resolverFactory == null)
28+
throw new ArgumentNullException(nameof(resolverFactory));
2929
var resolvers = resolverFactory(serviceProvider);
3030
ThrowHelper.ThrowIfCollectionNullOrEmpty(resolvers);
3131
_resolvers = resolvers;
3232
_logger = serviceProvider.GetService<ILoggerFactory>()?.CreateLogger(GetType());
3333
}
3434

3535
/// <inheritdoc/>
36-
public string ResolveName(IModReference modReference, CultureInfo culture)
36+
public string? ResolveName(IModReference modReference, CultureInfo culture)
3737
{
3838
if (modReference == null)
3939
throw new ArgumentNullException(nameof(modReference));
@@ -44,24 +44,19 @@ public string ResolveName(IModReference modReference, CultureInfo culture)
4444
{
4545
try
4646
{
47-
try
48-
{
49-
_logger?.LogDebug($"Resolving mod name with {nameResolver}");
50-
var name = nameResolver.ResolveName(modReference, culture);
51-
if (!string.IsNullOrEmpty(name))
52-
return name;
53-
}
54-
catch (Exception e)
55-
{
56-
throw new ModException(modReference, "Error while resolving a mod's name", e);
57-
}
47+
_logger?.LogDebug($"Resolving mod name with {nameResolver}");
48+
var name = nameResolver.ResolveName(modReference, culture);
49+
if (!string.IsNullOrEmpty(name))
50+
return name;
5851
}
59-
catch (ModException e)
52+
catch (Exception e)
6053
{
61-
_logger?.LogDebug(e, e.Message);
54+
_logger?.LogDebug(e, $"Error while resolving mod name for '{modReference}' with resolver {nameResolver.GetType()}: {e.Message}");
55+
throw;
6256
}
6357
}
6458

65-
throw new ModException(modReference, "Unable to resolve the mod's name.");
59+
_logger?.LogTrace($"Unable to resolve name for '{modReference}'");
60+
return null;
6661
}
6762
}

src/PetroGlyph.Games.EawFoc/src/Services/Name/Mods/IModNameResolver.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
using System.Globalization;
22
using EawModinfo.Spec;
3-
using PG.StarWarsGame.Infrastructure.Mods;
43

54
namespace PG.StarWarsGame.Infrastructure.Services.Name;
65

@@ -15,6 +14,5 @@ public interface IModNameResolver
1514
/// <param name="modReference">The game which name shall get resolved.</param>
1615
/// <param name="culture">The culture context.</param>
1716
/// <returns>The resolved name. May return <see langword="null"/> if no name for the <paramref name="culture"/> could be found.</returns>
18-
/// <exception cref="ModException">The mod's name could not be resolved.</exception>
19-
string ResolveName(IModReference modReference, CultureInfo culture);
17+
string? ResolveName(IModReference modReference, CultureInfo culture);
2018
}

src/PetroGlyph.Games.EawFoc/src/Services/Name/Mods/ModNameResolverBase.cs

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ protected ModNameResolverBase(IServiceProvider serviceProvider)
3232
}
3333

3434
/// <inheritdoc/>
35-
public string ResolveName(IModReference modReference, CultureInfo culture)
35+
public string? ResolveName(IModReference modReference, CultureInfo culture)
3636
{
3737
if (modReference == null)
3838
throw new ArgumentNullException(nameof(modReference));
@@ -43,19 +43,13 @@ public string ResolveName(IModReference modReference, CultureInfo culture)
4343
{
4444
var name = ResolveCore(modReference, culture);
4545
if (string.IsNullOrEmpty(name))
46-
throw new PetroglyphException($"Unable to resolve the mod's name {modReference}");
46+
Logger?.LogTrace($"Resolver '{this}' resolved null or empty name for '{modReference}'.");
4747
return name;
4848
}
49-
catch (PetroglyphException ex)
50-
{
51-
Logger?.LogError(ex, ex.Message);
52-
throw;
53-
}
5449
catch (Exception ex)
5550
{
56-
var e = new PetroglyphException($"Unable to resolve the mod's name {modReference}: {this}", ex);
57-
Logger?.LogError(e, e.Message);
58-
throw e;
51+
Logger?.LogError(ex, $"Resolver '{this}' had an error while resolving the name for {modReference}: {ex.Message}");
52+
throw;
5953
}
6054
}
6155

@@ -71,5 +65,5 @@ public override string ToString()
7165
/// <param name="modReference">The target <see cref="IModReference"/>.</param>
7266
/// <param name="culture">The target <see cref="CultureInfo"/>.</param>
7367
/// <returns>The resolved name or <see langword="null"/>.</returns>
74-
protected internal abstract string ResolveCore(IModReference modReference, CultureInfo culture);
68+
protected internal abstract string? ResolveCore(IModReference modReference, CultureInfo culture);
7569
}

src/PetroGlyph.Games.EawFoc/src/Services/Name/Mods/OfflineWorkshopNameResolver.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,13 @@ public OfflineWorkshopNameResolver(IServiceProvider serviceProvider) : base(serv
2323
}
2424

2525
/// <inheritdoc/>
26-
protected internal override string ResolveCore(IModReference modReference, CultureInfo culture)
26+
protected internal override string? ResolveCore(IModReference modReference, CultureInfo culture)
2727
{
2828
if (modReference.Type != ModType.Workshops)
2929
throw new NotSupportedException("Can only resolve for Steam Workshop mods!");
3030
if (!_steamHelper.ToSteamWorkshopsId(modReference.Identifier, out var modId))
3131
throw new ModException(modReference, $"Cannot get SteamID from workshops object {modReference.Identifier}");
3232

33-
return _workshopCache.ContainsMod(modId) ? _workshopCache.GetName(modId) : null!;
33+
return _workshopCache.ContainsMod(modId) ? _workshopCache.GetName(modId) : null;
3434
}
3535
}

src/PetroGlyph.Games.EawFoc/src/Services/Name/Mods/OnlineWorkshopNameResolver.cs

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using EawModinfo.Spec;
55
using HtmlAgilityPack;
66
using Microsoft.Extensions.DependencyInjection;
7+
using Microsoft.Extensions.Logging;
78
using PG.StarWarsGame.Infrastructure.Mods;
89
using PG.StarWarsGame.Infrastructure.Services.Steam;
910

@@ -26,7 +27,7 @@ public OnlineWorkshopNameResolver(IServiceProvider serviceProvider) : base(servi
2627
}
2728

2829
/// <inheritdoc/>
29-
protected internal override string ResolveCore(IModReference modReference, CultureInfo culture)
30+
protected internal override string? ResolveCore(IModReference modReference, CultureInfo culture)
3031
{
3132
if (modReference.Type != ModType.Workshops)
3233
throw new NotSupportedException("Can only resolve for Steam Workshop mods!");
@@ -42,21 +43,25 @@ protected internal override string ResolveCore(IModReference modReference, Cultu
4243
var downloader = ServiceProvider.GetService<ISteamWorkshopWebpageDownloader>() ??
4344
new SteamWorkshopWebpageDownloader();
4445
var modsWorkshopWebpage = downloader.GetSteamWorkshopsPageHtmlAsync(modId, culture).GetAwaiter().GetResult();
45-
if (modsWorkshopWebpage is null)
46-
throw new InvalidOperationException("Unable to get the mod's workshop web page.");
4746

48-
return GetName(modsWorkshopWebpage);
47+
if (modsWorkshopWebpage == null)
48+
{
49+
Logger?.LogTrace($"Unable to download website for Steam ID '{modId}'.");
50+
return null;
51+
}
52+
53+
return GetName(modsWorkshopWebpage, modId);
4954
})!;
5055
}
5156

52-
private static string GetName(HtmlDocument htmlDocument)
57+
private string? GetName(HtmlDocument htmlDocument, ulong modId)
5358
{
54-
if (htmlDocument == null)
55-
throw new ArgumentNullException(nameof(htmlDocument));
56-
5759
var node = htmlDocument.DocumentNode.SelectSingleNode("//div[contains(@class, 'workshopItemTitle')]");
5860
if (node is null)
59-
throw new InvalidOperationException("Unable to get name form Workshop's web page. Missing 'workshopItemTitle' node.");
61+
{
62+
Logger?.LogTrace($"Unable to find the item title on website for Steam ID '{modId}',");
63+
return null;
64+
}
6065
return node.InnerHtml;
6166
}
6267
}

src/PetroGlyph.Games.EawFoc/test/GameServices/EnglishGameNameResolverTest.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ public void IgnoreCulture()
1313
var resolver = new EnglishGameNameResolver();
1414
var id = new GameIdentity(GameType.Eaw, GamePlatform.SteamGold);
1515
resolver.ResolveName(id, CultureInfo.GetCultureInfo("de"));
16-
var name = resolver.ResolveName(id);
16+
var name = resolver.ResolveName(id, CultureInfo.CurrentCulture);
1717
Assert.Contains("Steam", name);
1818
Assert.Contains("Empire at War", name);
1919
}
@@ -23,7 +23,7 @@ public void EawSteamName()
2323
{
2424
var resolver = new EnglishGameNameResolver();
2525
var id = new GameIdentity(GameType.Eaw, GamePlatform.SteamGold);
26-
var name = resolver.ResolveName(id);
26+
var name = resolver.ResolveName(id, CultureInfo.InvariantCulture);
2727
Assert.Contains("Steam", name);
2828
Assert.Contains("Empire at War", name);
2929
}
@@ -33,7 +33,7 @@ public void FocSteamName()
3333
{
3434
var resolver = new EnglishGameNameResolver();
3535
var id = new GameIdentity(GameType.Foc, GamePlatform.SteamGold);
36-
var name = resolver.ResolveName(id);
36+
var name = resolver.ResolveName(id, CultureInfo.CurrentCulture);
3737
Assert.Contains("Steam", name);
3838
Assert.Contains("Corruption", name);
3939
}
@@ -43,7 +43,7 @@ public void DiskSteamName()
4343
{
4444
var resolver = new EnglishGameNameResolver();
4545
var id = new GameIdentity(GameType.Foc, GamePlatform.Disk);
46-
var name = resolver.ResolveName(id);
46+
var name = resolver.ResolveName(id, CultureInfo.InvariantCulture);
4747
Assert.DoesNotContain("Steam", name);
4848
Assert.Contains("Corruption", name);
4949
}

0 commit comments

Comments
 (0)