コード例 #1
0
        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");
            }
        }
コード例 #2
0
        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"));
        }
コード例 #3
0
        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");
            }
        }
コード例 #4
0
        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);
            }
        }
コード例 #5
0
        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();
            }
        }