Skip to content

Commit

Permalink
Added challenge spec sync for active or practice challenges on startu…
Browse files Browse the repository at this point in the history
…p. Partially addresses #267, but we can and should eventually do more.
  • Loading branch information
sei-bstein committed Oct 25, 2023
1 parent c4974a9 commit 471de9e
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 10 deletions.
26 changes: 26 additions & 0 deletions src/Gameboard.Api/Extensions/WebApplicationExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Gameboard.Api.Common.Services;
using Gameboard.Api.Features.Games;
using Gameboard.Api.Features.Hubs;
using Gameboard.Api.Hubs;
using Gameboard.Api.Services;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Npgsql.Replication;

namespace Gameboard.Api.Extensions;

Expand Down Expand Up @@ -52,4 +59,23 @@ public static WebApplication ConfigureGameboard(this WebApplication app, AppSett

return app;
}

public static WebApplication SyncActiveSpecsOnStartup(this WebApplication app, ILogger logger)
{
Task.Run(async () =>
{
try
{
using var scope = app.Services.CreateScope();
var challengeSpecService = scope.ServiceProvider.GetRequiredService<ChallengeSpecService>();
await challengeSpecService.SyncActiveSpecs(CancellationToken.None);
}
catch (Exception ex)
{
logger.LogError(message: "Failed to synchronize active challenge specs on startup.", exception: ex);
}
});

return app;
}
}
53 changes: 47 additions & 6 deletions src/Gameboard.Api/Features/ChallengeSpec/ChallengeSpecService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Threading;
using System.Threading.Tasks;
using AutoMapper;
using Gameboard.Api.Common.Services;
using Gameboard.Api.Data;
using Gameboard.Api.Features.GameEngine;
using Microsoft.EntityFrameworkCore;
Expand All @@ -15,18 +16,21 @@ namespace Gameboard.Api.Services;

public class ChallengeSpecService : _Service
{
private readonly INowService _now;
private readonly IStore _store;
IGameEngineService GameEngine { get; }

public ChallengeSpecService
(
ILogger<ChallengeSpecService> logger,
IMapper mapper,
INowService now,
CoreOptions options,
IStore store,
IGameEngineService gameEngine
) : base(logger, mapper, options)
{
_now = now;
_store = store;
GameEngine = gameEngine;
}
Expand Down Expand Up @@ -83,8 +87,7 @@ public async Task<IEnumerable<BoardSpec>> ListGameSpecs(string gameId)

public async Task Sync(string id)
{
var externals = (await GameEngine.ListSpecs(new SearchFilter()))
.ToDictionary(o => o.ExternalId);
var externals = await LoadExternalSpecsForSync();

var specs = _store
.WithTracking<Data.ChallengeSpec>()
Expand All @@ -95,12 +98,50 @@ public async Task Sync(string id)
if (externals.ContainsKey(spec.ExternalId).Equals(false))
continue;

spec.Name = externals[spec.ExternalId].Name;
spec.Description = externals[spec.ExternalId].Description;
spec.Tags = externals[spec.ExternalId].Tags;
spec.Text = externals[spec.ExternalId].Text;
SyncSpec(spec, externals[spec.ExternalId]);
}

await _store.SaveUpdateRange(specs.ToArray());
}

/// <summary>
/// Updates "active" challenge specs with information from the appropriate
/// game engine (for now, only Topomojo.)
///
/// "Active" here is defined as specs that are used by a game with a current
/// execution period and
/// </summary>
/// <returns></returns>
public async Task SyncActiveSpecs(CancellationToken cancellationToken)
{
var nowish = _now.Get();
var activeSpecs = await _store
.WithTracking<Data.ChallengeSpec>()
.Where(s => s.Game.GameEnd > nowish || s.Game.PlayerMode == PlayerMode.Practice)
.ToArrayAsync(cancellationToken);

var externalSpecs = await LoadExternalSpecsForSync();

foreach (var spec in activeSpecs)
{
if (externalSpecs.ContainsKey(spec.ExternalId))
SyncSpec(spec, externalSpecs[spec.ExternalId]);
}

await _store.SaveUpdateRange(activeSpecs);
}

internal async Task<IDictionary<string, ExternalSpec>> LoadExternalSpecsForSync()
{
return (await GameEngine.ListSpecs(new SearchFilter()))
.ToDictionary(o => o.ExternalId);
}

internal void SyncSpec(Data.ChallengeSpec spec, ExternalSpec externalSpec)
{
spec.Name = externalSpec.Name;
spec.Description = externalSpec.Description;
spec.Tags = externalSpec.Tags;
spec.Text = externalSpec.Text;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,14 @@ public async Task<SearchPracticeChallengesResult> Handle(SearchPracticeChallenge
q = q.OrderBy(s => s.Name);
var results = await _mapper.ProjectTo<ChallengeSpecSummary>(q).ToArrayAsync(cancellationToken);

// fix up relative urls
foreach (var result in results)
{
// hide tags which aren't in the "suggested searches" configured in the practice area
// (this is because topo has lots of tags that aren't useful to players, so we only)
// want to show them values in the suggested search
result.Tags = result.Tags.Where(t => sluggedSuggestedSearches.Contains(_slugger.Get(t)));

// fix up relative urls
result.Text = _challengeDocsService.ReplaceRelativeUris(result.Text);
}

Expand Down
1 change: 0 additions & 1 deletion src/Gameboard.Api/Features/UnityGames/UnityGameService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
using System.Threading.Tasks;
using AutoMapper;
using Gameboard.Api.Data;
using Gameboard.Api.Data.Abstractions;
using Gameboard.Api.Features.Games;
using Gameboard.Api.Features.Games.External;
using Gameboard.Api.Features.Teams;
Expand Down
3 changes: 2 additions & 1 deletion src/Gameboard.Api/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@
var app = builder.Build();
app
.InitializeDatabase(settings, app.Logger)
.ConfigureGameboard(settings);
.ConfigureGameboard(settings)
.SyncActiveSpecsOnStartup(app.Logger);

// start!
startupLogger.LogInformation("Let the games begin!");
Expand Down

0 comments on commit 471de9e

Please sign in to comment.