public async Task HandleHackResultAsync( Guid statemachineId, CancellationToken token) { var statemachine = await _mgmt.GetStateMachineInstanceAsync(statemachineId, token); if (statemachine.Name == "HackStateMachine") { await HandlePlainHackAsync(statemachine, token); } else if (statemachine.Name == "HackAllStateMachine") // Contest only { await HandleContestHackAsync(statemachine, token); } else { throw new InvalidOperationException(statemachine.Name + " is invalid"); } }
public async Task <IActionResult> LeetCode( [FromServices] ManagementServiceClient MgmtSvc, Guid id) { var statemachine = await MgmtSvc.GetStateMachineInstanceAsync(id, default(CancellationToken)); var actors = statemachine.StartedActors.Where(x => x.Name == "LeetCodePullProblemBodyActor" && x.Outputs.Any(y => y.Name == "problem.json")).ToDictionary(x => "leetcode-" + x.Tag); var ids = actors.Keys.Select(x => x).ToList(); foreach (var i in ids) { var model = JsonConvert.DeserializeObject <ProblemJson>(Encoding.UTF8.GetString((await ManagementService.GetBlobAsync(actors[i].Outputs.Single(x => x.Name == "problem.json").Id)).Body)); var problem = await DB.Problems.SingleOrDefaultAsync(x => x.Id == i); if (problem == null) { problem = new Problem { Title = model.Title, Id = i, Body = model.Body, Source = ProblemSource.LeetCode, Tags = "按题库:LeetCode", TimeLimitationPerCaseInMs = model.TimeLimitInMs, MemoryLimitationPerCaseInByte = model.MemoryLimitInByte, IsVisible = true, Template = JsonConvert.SerializeObject(model.CodeTemplate) }; DB.Problems.Add(problem); } else { problem.Title = model.Title; problem.Body = model.Body; problem.TimeLimitationPerCaseInMs = model.TimeLimitInMs; problem.MemoryLimitationPerCaseInByte = model.MemoryLimitInByte; problem.IsVisible = true; } await DB.SaveChangesAsync(); } return(Result(200, "ok")); }
public async Task <StateMachineInstanceOutputDto> GetStateMachineResultAsync(Guid statemachineId, bool forcePolling = false, CancellationToken token = default(CancellationToken)) { if (_configuration["ManagementService:Mode"] == "Polling" || forcePolling) { var retryCount = 30; while (--retryCount >= 0) { await Task.Delay(1000); var result = await _managementServiceClient.GetStateMachineInstanceAsync(statemachineId, token); if (result.Status != ManagementService.Model.Enums.StateMachineStatus.Running) { return(result); } } throw new Exception("Polling State Machine Failed, ID=" + statemachineId); } else if (_configuration["ManagementService:Mode"] == "Callback") { var taskCompletionSource = new TaskCompletionSource <StateMachineInstanceOutputDto>(); token.Register(() => { TaskCompletionSource <StateMachineInstanceOutputDto> semaphore; if (Semaphores.TryRemove(statemachineId, out semaphore)) { semaphore.TrySetCanceled(); } }); Semaphores.AddOrUpdate(statemachineId, taskCompletionSource, (a, b) => taskCompletionSource); return(await taskCompletionSource.Task); } else { throw new InvalidOperationException(_configuration["ManagementService:Mode"] + " is invalid"); } }
public async Task HandleJudgeResultAsync( Guid statemachineId, CancellationToken token) { bool isAccepted = false; var statemachine = await _mgmt.GetStateMachineInstanceAsync(statemachineId, token); if (statemachine.Status == ManagementService.Model.Enums.StateMachineStatus.Running && statemachine.Stage != "Finally") { throw new InvalidOperationException("The statemachine status is: " + statemachine.Status.ToString()); } var statusStatemachineRelation = (await _db.JudgeStatusStateMachines.FirstOrDefaultAsync(x => x.StateMachineId == statemachineId, token)); if (statusStatemachineRelation == null) { throw new KeyNotFoundException("Did not find the status which related to the statemachine " + statemachineId); } var statusId = statusStatemachineRelation.StatusId; var status = await _db.JudgeStatuses .AsNoTracking() .Where(x => x.Id == statusId) .Select(x => new { x.ProblemId, x.UserId, x.IsSelfTest, x.ContestId, x.Id }) .FirstOrDefaultAsync(token); var userId = status.UserId; var problemId = status.ProblemId; var isSelfTest = status.IsSelfTest; if (statemachine.Status == ManagementService.Model.Enums.StateMachineStatus.Failed) { _db.JudgeStatuses .Where(x => x.Id == statusId) .SetField(x => x.Hint).WithValue(statemachine.Exception) .SetField(x => x.Result).WithValue(JudgeResult.SystemError) .Update(); } _db.Problems .Where(x => x.Id == problemId) .SetField(x => x.CachedSubmitCount).Plus(1) .Update(); var problem = await _db.Problems.SingleAsync(x => x.Id == problemId, token); #region Local Judge if (problem.Source == ProblemSource.Local) { var compileResult = await IsFailedInCompileStageAsync(statemachine, token); if (compileResult.result) { _db.JudgeStatuses .Where(x => x.Id == statusId) .SetField(x => x.Result).WithValue((int)JudgeResult.CompileError) .SetField(x => x.Hint).WithValue(compileResult.hint) .Update(); _db.SubJudgeStatuses .Where(x => x.StatusId == statusId) .SetField(x => x.Result).WithValue((int)JudgeResult.CompileError) .Update(); } else { var runtimeResult = await HandleRuntimeResultAsync(statemachine, problem.MemoryLimitationPerCaseInByte, token); var finalResult = runtimeResult.Max(x => x.result); var finalTime = runtimeResult.Sum(x => x.time); var finalMemory = runtimeResult.Max(x => x.memory); _db.JudgeStatuses .Where(x => x.Id == statusId) .SetField(x => x.BinaryBlobId).WithValue(Guid.Parse(compileResult.hint)) .SetField(x => x.TimeUsedInMs).WithValue(finalTime) .SetField(x => x.MemoryUsedInByte).WithValue(finalMemory) .SetField(x => x.Result).WithValue((int)finalResult) .Update(); for (var i = 0; i < runtimeResult.Count(); i++) { _db.SubJudgeStatuses .Where(x => x.StatusId == statusId) .Where(x => x.SubId == i) .SetField(x => x.TimeUsedInMs).WithValue(runtimeResult.ElementAt(i).time) .SetField(x => x.MemoryUsedInByte).WithValue(runtimeResult.ElementAt(i).memory) .SetField(x => x.Result).WithValue((int)runtimeResult.ElementAt(i).result) .SetField(x => x.Hint).WithValue(runtimeResult.ElementAt(i).hint) .Update(); } if (finalResult == JudgeResult.Accepted) { isAccepted = true; } } if (!isSelfTest && string.IsNullOrEmpty(status.ContestId)) { UpdateUserProblemJson(userId, problem.Id, isAccepted); if (isAccepted) { _db.Problems .Where(x => x.Id == problemId) .SetField(x => x.CachedAcceptedCount).Plus(1) .Update(); } } } #endregion #region Virtual Judge else { _db.VirtualJudgeUsers .Where(x => x.LockerId == statusId) .SetField(x => x.LockerId).WithValue(null) .Update(); var resultBody = JsonConvert.DeserializeObject <VirtualJudgeResult>(Encoding.UTF8.GetString((await _mgmt.GetBlobAsync(statemachine.StartedActors.Last().Outputs.Single(x => x.Name == "result.json").Id, token)).Body)); var judgeResult = (Enum.Parse <JudgeResult>(resultBody.Result.Replace(" ", ""))); _db.JudgeStatuses .Where(x => x.Id == statusId) .SetField(x => x.TimeUsedInMs).WithValue(resultBody.TimeUsedInMs) .SetField(x => x.MemoryUsedInByte).WithValue(resultBody.MemoryUsedInByte) .SetField(x => x.Result).WithValue((int)judgeResult) .SetField(x => x.Hint).WithValue(resultBody.Hint) .Update(); // Handle sub-status if (resultBody.SubStatuses != null && resultBody.SubStatuses.Count() > 0) { foreach (var x in resultBody.SubStatuses) { _db.SubJudgeStatuses.Add(new SubJudgeStatus { SubId = x.SubId, Result = Enum.Parse <JudgeResult>(x.Result), TimeUsedInMs = (int)x.TimeUsedInMs, MemoryUsedInByte = (int)x.MemoryUsedInByte, StatusId = statusId, Hint = x.Hint }); } } else { _db.SubJudgeStatuses.Add(new SubJudgeStatus { SubId = 1, Result = Enum.Parse <JudgeResult>(resultBody.Result), TimeUsedInMs = (int)resultBody.TimeUsedInMs, MemoryUsedInByte = (int)resultBody.MemoryUsedInByte, StatusId = statusId, Hint = $"{ problem.Source }不支持查看测试点信息" }); } _db.SaveChanges(); if (string.IsNullOrEmpty(status.ContestId)) { UpdateUserProblemJson(userId, problem.Id, judgeResult == JudgeResult.Accepted); if (judgeResult == JudgeResult.Accepted) { _db.Problems .Where(x => x.Id == problemId) .SetField(x => x.CachedAcceptedCount).Plus(1) .Update(); } } } #endregion if (!string.IsNullOrEmpty(status.ContestId)) { var ce = _cef.Create(status.ContestId); ce.OnJudgeCompleted(_db.JudgeStatuses .Include(x => x.SubStatuses) .Single(x => x.Id == status.Id)); if (ce.PushNotificationSetting == PushNotificationType.All) { _hub.Clients.All.InvokeAsync("ItemUpdated", "judge", statusId); _hub.Clients.All.InvokeAsync("StandingsUpdated", status.ContestId, status.UserId); } else if (ce.PushNotificationSetting == PushNotificationType.Master) { _hub.Clients.Group("Masters").InvokeAsync("ItemUpdated", "judge", statusId); foreach (var x in ce.GetContestOwners()) { _hub.Clients.User(x).InvokeAsync("ItemUpdated", "judge", statusId); } } } else { _hub.Clients.All.InvokeAsync("ItemUpdated", "judge", statusId); } }
public override void OnHackCompleted(HackStatus status) { if (status.Result == HackResult.Succeeded) { // 1. Set the status to be non-hackable DB.ContestProblemLastStatuses .Where(x => x.StatusId == status.JudgeStatusId && x.ContestId == ContestId) .SetField(x => x.IsHackable).WithValue(false) .SetField(x => x.IsHacked).WithValue(true) .Update(); // 2. Add the hack data to problem var input = status.HackDataBlobId.Value; var testCase = DB.TestCases.FirstOrDefault(x => x.InputBlobId == input && x.ProblemId == status.Status.ProblemId); var testCaseExisted = testCase != null; if (!testCaseExisted) { var inputLength = ManagementService.GetBlobAsync(input).Result.Body.Length; var stateMachine = ManagementService.GetStateMachineInstanceAsync(status.RelatedStateMachineIds.Last().StateMachineId).Result; var output = stateMachine.StartedActors.First(x => x.Tag == "Standard").Outputs.First(x => x.Name == "stdout.txt").Id; var outputLength = ManagementService.GetBlobAsync(output).Result.Body.Length; testCase = new TestCase { ContestId = ContestId, InputBlobId = input, InputSizeInByte = inputLength, OutputBlobId = output, OutputSizeInByte = outputLength, ProblemId = status.Status.ProblemId, Type = TestCaseType.Hack }; DB.TestCases.Add(testCase); DB.SaveChanges(); } // 3. Add the result into sub judge status if (!testCaseExisted) { var sub = new SubJudgeStatus { SubId = DB.SubJudgeStatuses.Where(x => x.StatusId == status.JudgeStatusId).Count(), Hint = status.Hint, MemoryUsedInByte = status.MemoryUsedInByte, TimeUsedInMs = status.TimeUsedInMs, Result = status.HackeeResult, InputBlobId = testCase.InputBlobId, OutputBlobId = testCase.OutputBlobId, TestCaseId = testCase.Id, StatusId = status.JudgeStatusId }; DB.SubJudgeStatuses.Add(sub); DB.SaveChanges(); } // 4. Add point for the hacker DB.ContestProblemLastStatuses .Where(x => x.ContestId == ContestId && x.ProblemId == status.Status.ProblemId && x.UserId == status.UserId) .SetField(x => x.Point2).Plus(1) .Update(); // 5. Hack all statuses if (!testCaseExisted && DB.Attendees.Any(x => x.ContestId == ContestId && x.UserId == status.UserId && !x.IsVirtual)) { var affectedStatuses = DB.ContestProblemLastStatuses .Include(x => x.Status) .Where(x => x.ProblemId == status.Status.ProblemId && x.ContestId == ContestId && x.Status.BinaryBlobId.HasValue && x.IsAccepted) .ToList(); var problem = DB.Problems.Single(x => x.Id == status.Status.ProblemId); var validatorId = problem.ValidatorBlobId.HasValue ? problem.ValidatorBlobId.Value : Guid.Parse(Configuration["JoyOI:StandardValidatorBlobId"]); var blobs = new List <BlobInfo>(affectedStatuses.Count + 10); blobs.Add(new BlobInfo { Id = ManagementService.PutBlobAsync("limit.json", Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(new { UserTime = status.Status.Problem.TimeLimitationPerCaseInMs, PhysicalTime = status.Status.Problem.TimeLimitationPerCaseInMs * 4, Memory = status.Status.Problem.MemoryLimitationPerCaseInByte }))).Result, Name = "limit.json", Tag = "Problem=" + status.Status.ProblemId }); blobs.Add(new BlobInfo(validatorId, problem.ValidatorBlobId.HasValue ? "Validator" + Constants.GetBinaryExtension(problem.ValidatorLanguage) : "Validator.out")); blobs.Add(new BlobInfo(status.HackDataBlobId.Value, "data.txt", testCase.Id.ToString())); blobs.Add(new BlobInfo(testCase.OutputBlobId, "std.txt", testCase.Id.ToString())); foreach (var x in affectedStatuses) { blobs.Add(new BlobInfo(x.Status.BinaryBlobId.Value, "Hackee" + Constants.GetBinaryExtension(x.Status.Language), x.StatusId.ToString())); } ManagementService.PutStateMachineInstanceAsync("HackAllStateMachine", Configuration["ManagementService:CallBack"], blobs, 2); } } else if (status.Result == HackResult.Failed) { DB.ContestProblemLastStatuses .Where(x => x.ContestId == ContestId && x.ProblemId == status.Status.ProblemId && x.UserId == status.UserId) .SetField(x => x.Point2).Subtract(1) .SetField(x => x.Point3).Plus(1) .Update(); } }