Skip to content

Commit

Permalink
perf: always load flags later
Browse files Browse the repository at this point in the history
  • Loading branch information
GZTimeWalker committed Nov 21, 2024
1 parent e28ad05 commit b4b57ea
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 49 deletions.
48 changes: 29 additions & 19 deletions src/GZCTF/Controllers/EditController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -297,11 +297,13 @@ public async Task<IActionResult> DeleteGameWriteUps([FromRoute] int id, Cancella
[ProducesResponseType(typeof(RequestResponse), StatusCodes.Status404NotFound)]
public async Task<IActionResult> UpdateGamePoster([FromRoute] int id, IFormFile file, CancellationToken token)
{
if (file.Length == 0)
return BadRequest(new RequestResponse(localizer[nameof(Resources.Program.File_SizeZero)]));

if (file.Length > 3 * 1024 * 1024)
return BadRequest(new RequestResponse(localizer[nameof(Resources.Program.File_SizeTooLarge)]));
switch (file.Length)
{
case 0:
return BadRequest(new RequestResponse(localizer[nameof(Resources.Program.File_SizeZero)]));
case > 3 * 1024 * 1024:
return BadRequest(new RequestResponse(localizer[nameof(Resources.Program.File_SizeTooLarge)]));
}

Game? game = await gameRepository.GetGameById(id, token);

Expand Down Expand Up @@ -529,16 +531,17 @@ public async Task<IActionResult> GetGameChallenge([FromRoute] int id, [FromRoute
return NotFound(new RequestResponse(localizer[nameof(Resources.Program.Game_NotFound)],
StatusCodes.Status404NotFound));

GameChallenge? res = await challengeRepository.GetChallenge(id, cId, false, token);
GameChallenge? challenge = await challengeRepository.GetChallenge(id, cId, token);

if (res is null)
if (challenge is null)
return NotFound(new RequestResponse(localizer[nameof(Resources.Program.Challenge_NotFound)],
StatusCodes.Status404NotFound));

if (res.Type != ChallengeType.DynamicContainer)
res.Flags = (await challengeRepository.GetFlags(res.Id, token)).ToList();
// do not load flags for dynamic containers
if (challenge.Type != ChallengeType.DynamicContainer)
await challengeRepository.LoadFlags(challenge, token);

return Ok(ChallengeEditDetailModel.FromChallenge(res));
return Ok(ChallengeEditDetailModel.FromChallenge(challenge));
}

/// <summary>
Expand All @@ -564,15 +567,20 @@ public async Task<IActionResult> UpdateGameChallenge([FromRoute] int id, [FromRo
return NotFound(new RequestResponse(localizer[nameof(Resources.Program.Game_NotFound)],
StatusCodes.Status404NotFound));

GameChallenge? res = await challengeRepository.GetChallenge(id, cId, true, token);
GameChallenge? res = await challengeRepository.GetChallenge(id, cId, token);

if (res is null)
return NotFound(new RequestResponse(localizer[nameof(Resources.Program.Challenge_NotFound)],
StatusCodes.Status404NotFound));

// NOTE: IsEnabled can only be updated outside the edit page
if (model.IsEnabled == true && res.Flags.Count == 0 && res.Type != ChallengeType.DynamicContainer)
return BadRequest(new RequestResponse(localizer[nameof(Resources.Program.Challenge_NoFlag)]));
if (model.IsEnabled is true && !res.IsEnabled && res.Type != ChallengeType.DynamicContainer)
{
await challengeRepository.LoadFlags(res, token);

if (res.Flags.Count == 0)
return BadRequest(new RequestResponse(localizer[nameof(Resources.Program.Challenge_NoFlag)]));
}

if (model.EnableTrafficCapture is true && !res.Type.IsContainer())
return BadRequest(new RequestResponse(localizer[nameof(Resources.Program.Challenge_CaptureNotAllowed)]));
Expand Down Expand Up @@ -639,7 +647,7 @@ public async Task<IActionResult> CreateTestContainer([FromRoute] int id, [FromRo
return NotFound(new RequestResponse(localizer[nameof(Resources.Program.Game_NotFound)],
StatusCodes.Status404NotFound));

GameChallenge? challenge = await challengeRepository.GetChallenge(id, cId, true, token);
GameChallenge? challenge = await challengeRepository.GetChallenge(id, cId, token);

if (challenge is null)
return NotFound(new RequestResponse(localizer[nameof(Resources.Program.Challenge_NotFound)],
Expand Down Expand Up @@ -705,7 +713,7 @@ public async Task<IActionResult> DestroyTestContainer([FromRoute] int id, [FromR
return NotFound(new RequestResponse(localizer[nameof(Resources.Program.Game_NotFound)],
StatusCodes.Status404NotFound));

GameChallenge? challenge = await challengeRepository.GetChallenge(id, cId, true, token);
GameChallenge? challenge = await challengeRepository.GetChallenge(id, cId, token);

if (challenge is null)
return NotFound(new RequestResponse(localizer[nameof(Resources.Program.Challenge_NotFound)],
Expand Down Expand Up @@ -741,7 +749,7 @@ public async Task<IActionResult> RemoveGameChallenge([FromRoute] int id, [FromRo
return NotFound(new RequestResponse(localizer[nameof(Resources.Program.Game_NotFound)],
StatusCodes.Status404NotFound));

GameChallenge? res = await challengeRepository.GetChallenge(id, cId, true, token);
GameChallenge? res = await challengeRepository.GetChallenge(id, cId, token);

if (res is null)
return NotFound(new RequestResponse(localizer[nameof(Resources.Program.Challenge_NotFound)],
Expand Down Expand Up @@ -778,7 +786,7 @@ public async Task<IActionResult> UpdateAttachment([FromRoute] int id, [FromRoute
return NotFound(new RequestResponse(localizer[nameof(Resources.Program.Game_NotFound)],
StatusCodes.Status404NotFound));

GameChallenge? challenge = await challengeRepository.GetChallenge(id, cId, true, token);
GameChallenge? challenge = await challengeRepository.GetChallenge(id, cId, token);

if (challenge is null)
return NotFound(new RequestResponse(localizer[nameof(Resources.Program.Challenge_NotFound)],
Expand Down Expand Up @@ -816,12 +824,13 @@ public async Task<IActionResult> AddFlags([FromRoute] int id, [FromRoute] int cI
return NotFound(new RequestResponse(localizer[nameof(Resources.Program.Game_NotFound)],
StatusCodes.Status404NotFound));

GameChallenge? challenge = await challengeRepository.GetChallenge(id, cId, true, token);
GameChallenge? challenge = await challengeRepository.GetChallenge(id, cId, token);

if (challenge is null)
return NotFound(new RequestResponse(localizer[nameof(Resources.Program.Challenge_NotFound)],
StatusCodes.Status404NotFound));

await challengeRepository.LoadFlags(challenge, token);
await challengeRepository.AddFlags(challenge, models, token);

return Ok();
Expand Down Expand Up @@ -850,12 +859,13 @@ public async Task<IActionResult> RemoveFlag([FromRoute] int id, [FromRoute] int
return NotFound(new RequestResponse(localizer[nameof(Resources.Program.Game_NotFound)],
StatusCodes.Status404NotFound));

GameChallenge? challenge = await challengeRepository.GetChallenge(id, cId, true, token);
GameChallenge? challenge = await challengeRepository.GetChallenge(id, cId, token);

if (challenge is null)
return NotFound(new RequestResponse(localizer[nameof(Resources.Program.Challenge_NotFound)],
StatusCodes.Status404NotFound));

await challengeRepository.LoadFlags(challenge, token);
return Ok(await challengeRepository.RemoveFlag(challenge, fId, token));
}
}
5 changes: 4 additions & 1 deletion src/GZCTF/Controllers/GameController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1190,13 +1190,16 @@ async Task<ContextInfo> GetContextInfo(int id, int challengeId = 0, bool withFla
if (challengeId <= 0)
return res;

GameChallenge? challenge = await challengeRepository.GetChallenge(id, challengeId, withFlag, token);
GameChallenge? challenge = await challengeRepository.GetChallenge(id, challengeId, token);

if (challenge is null)
return res.WithResult(NotFound(new RequestResponse(
localizer[nameof(Resources.Program.Challenge_NotFound)],
StatusCodes.Status404NotFound)));

if (withFlag)
await challengeRepository.LoadFlags(challenge, token);

res.Challenge = challenge;

return res;
Expand Down
3 changes: 2 additions & 1 deletion src/GZCTF/Controllers/ProxyController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,8 @@ void LogProxyResult(Guid id, IPEndPoint client, IPEndPoint target, ulong tx, ulo
}
rx += (ulong)count;
await ws.SendAsync(buffer.AsMemory(0, count), WebSocketMessageType.Binary, true, ct);
await ws.SendAsync(
buffer.AsMemory(0, count), WebSocketMessageType.Binary, true, ct);
}
}
catch (TaskCanceledException) { }
Expand Down
29 changes: 10 additions & 19 deletions src/GZCTF/Repositories/GameChallengeRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,22 +47,12 @@ public async Task<bool> EnsureInstances(GameChallenge challenge, Game game, Canc
return update;
}

public Task<GameChallenge?> GetChallenge(int gameId, int id, bool withFlag = false,
CancellationToken token = default)
{
IQueryable<GameChallenge> challenges = Context.GameChallenges
.Where(c => c.Id == id && c.GameId == gameId);

if (withFlag)
challenges = challenges.Include(e => e.Flags);
public Task<GameChallenge?> GetChallenge(int gameId, int id, CancellationToken token = default)
=> Context.GameChallenges
.Where(c => c.Id == id && c.GameId == gameId).FirstOrDefaultAsync(token);

return challenges.FirstOrDefaultAsync(token);
}

public Task<FlagContext[]> GetFlags(int challengeId, CancellationToken token = default) =>
Context.FlagContexts
.Where(c => c.Id == challengeId)
.ToArrayAsync(token);
public Task LoadFlags(GameChallenge challenge, CancellationToken token = default) =>
Context.Entry(challenge).Collection(c => c.Flags).LoadAsync(token);

public Task<GameChallenge[]> GetChallenges(int gameId, CancellationToken token = default) =>
Context.GameChallenges.Where(c => c.GameId == gameId).OrderBy(c => c.Id).ToArrayAsync(token);
Expand Down Expand Up @@ -116,10 +106,11 @@ public async Task<bool> RecalculateAcceptedCount(Game game, CancellationToken to

await Context.GameChallenges.IgnoreAutoIncludes()
.Where(c => query.Any(r => r.ChallengeId == c.Id))
.ExecuteUpdateAsync(setter =>
setter.SetProperty(
c => c.AcceptedCount,
c => query.First(r => r.ChallengeId == c.Id).Count),
.ExecuteUpdateAsync(
setter =>
setter.SetProperty(
c => c.AcceptedCount,
c => query.First(r => r.ChallengeId == c.Id).Count),
token);

await cacheHelper.FlushScoreboardCache(game.Id, token);
Expand Down
16 changes: 7 additions & 9 deletions src/GZCTF/Repositories/Interface/IGameChallengeRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,23 +31,22 @@ public interface IGameChallengeRepository : IRepository
public Task<GameChallenge[]> GetChallenges(int gameId, CancellationToken token = default);

/// <summary>
/// 获取题目
/// 获取题目信息,不包含 Flag
/// </summary>
/// <param name="gameId">比赛Id</param>
/// <param name="id">题目Id</param>
/// <param name="withFlag">是否加载Flag</param>
/// <param name="token"></param>
/// <returns></returns>
public Task<GameChallenge?> GetChallenge(int gameId, int id, bool withFlag = false,
CancellationToken token = default);
public Task<GameChallenge?> GetChallenge(int gameId, int id, CancellationToken token = default);

/// <summary>
/// 获取 Flags
/// 加载 Flags
/// </summary>
/// <param name="challengeId">题目Id</param>
/// <param name="challenge">题目</param>
/// <param name="token"></param>
/// <returns></returns>
public Task<FlagContext[]> GetFlags(int challengeId, CancellationToken token = default);
public Task LoadFlags(GameChallenge challenge, CancellationToken token = default);

/// <summary>
/// 获取全部需要捕获流量的题目
/// </summary>
Expand Down Expand Up @@ -81,8 +80,7 @@ public interface IGameChallengeRepository : IRepository
/// <param name="model">附件信息</param>
/// <param name="token"></param>
/// <returns></returns>
public Task UpdateAttachment(GameChallenge challenge, AttachmentCreateModel model,
CancellationToken token = default);
public Task UpdateAttachment(GameChallenge challenge, AttachmentCreateModel model, CancellationToken token = default);

/// <summary>
/// 删除 Flag,确保 Flags 字段已加载
Expand Down

0 comments on commit b4b57ea

Please sign in to comment.