Пример #1
0
        public async Task <IActionResult> GetTestCase(
            [FromServices] ManagementServiceClient MgmtSvc,
            string problemId,
            string contestId,
            TestCaseType?type,
            bool?showContent,
            CancellationToken token)
        {
            this.HasOwnership = await HasPermissionToProblemAsync(problemId, token);

            var problem = await DB.Problems.SingleOrDefaultAsync(x => x.Id == problemId, token);

            if (!string.IsNullOrEmpty(contestId) && !await IsContestAttendeeAbleToAccessProblem(problemId, contestId, token))
            {
                return(Result(403, "You don't have the permission to view this problem."));
            }
            if ((problem == null || !problem.IsVisible && !this.HasOwnership) && string.IsNullOrEmpty(contestId))
            {
                return(Result <Problem>(404, "Not Found"));
            }

            IQueryable <TestCase> testCases = DB.TestCases
                                              .Where(x => x.ProblemId == problemId);

            if (type.HasValue)
            {
                testCases = testCases.Where(x => x.Type == type.Value);
            }

            testCases = testCases.OrderBy(x => x.Type);

            var ret = await testCases.Select(x => new TestCaseWithContent
            {
                Id               = x.Id,
                ContestId        = x.ContestId,
                InputBlobId      = x.InputBlobId,
                InputSizeInByte  = x.InputSizeInByte,
                OutputBlobId     = x.OutputBlobId,
                OutputSizeInByte = x.OutputSizeInByte,
                ProblemId        = x.ProblemId,
                Type             = x.Type
            })
                      .ToListAsync(token);

            if (showContent.HasValue && showContent.Value)
            {
                foreach (var x in ret)
                {
                    if (x.Type == TestCaseType.Sample || await IsAbleToAccessTestCaseContentAsync(x.ProblemId, token))
                    {
                        x.Input  = Encoding.UTF8.GetString((await MgmtSvc.GetBlobAsync(x.InputBlobId, token)).Body);
                        x.Output = Encoding.UTF8.GetString((await MgmtSvc.GetBlobAsync(x.OutputBlobId, token)).Body);
                    }
                }
            }

            return(Result(ret));
        }
Пример #2
0
        static async Task MainAsync(CancellationToken token)
        {
            var connStr = JsonConvert.DeserializeObject <dynamic>(File.ReadAllText("config.json")).Oj;
            var builder = new DbContextOptionsBuilder <OnlineJudgeContext>();

            builder.UseMySql((string)connStr);
            var cnt = 0;

            using (var db = new OnlineJudgeContext(builder.Options))
            {
                var problemIds = await db.Problems
                                 .Where(x => x.Source == ProblemSource.Local)
                                 .Select(x => x.Id)
                                 .ToListAsync(token);

                var mgmt = new ManagementServiceClient("https://mgmtsvc.1234.sh", @"C:\Users\Yuko\Documents\webapi-client.pfx", "123456");

                var tasks  = new List <Task>();
                var cancel = new CancellationTokenSource();
                var ret    = new ConcurrentBag <(string, Guid)>();
                foreach (var id in problemIds)
                {
                    cnt++;
                    if (cnt % 10 == 0)
                    {
                        Console.WriteLine(cnt + " problems handled.");
                    }

                    foreach (var x in await db.TestCases.Where(x => x.ProblemId == id).ToListAsync(token))
                    {
                        tasks.Add(Task.Run(async() => {
                            try
                            {
                                await mgmt.GetBlobAsync(x.InputBlobId);
                            }
                            catch
                            {
                                ret.Add((x.ProblemId, x.InputBlobId));
                                Console.WriteLine("[Failed] " + x.ProblemId + ", input id = " + x.InputBlobId);
                            }
                            try
                            {
                                await mgmt.GetBlobAsync(x.OutputBlobId);
                            }
                            catch
                            {
                                ret.Add((x.ProblemId, x.OutputBlobId));
                                Console.WriteLine("[Failed] " + x.ProblemId + ", output id = " + x.OutputBlobId);
                            }
                        }));
                    }
                    await Task.WhenAll(tasks);
                }

                File.WriteAllText("result.txt", string.Join("\r\n", ret.Select(x => x.Item1 + " " + x.Item2)));
            }
        }
Пример #3
0
        public async Task <IActionResult> GetTestCase(
            [FromServices] ManagementServiceClient MgmtSvc,
            string problemId,
            Guid id,
            bool?showContent,
            CancellationToken token)
        {
            this.HasOwnership = await HasPermissionToProblemAsync(problemId, token);

            var problem = await DB.Problems.SingleOrDefaultAsync(x => x.Id == problemId, token);

            if (problem == null || !problem.IsVisible && !this.HasOwnership)
            {
                return(Result <Problem>(404, "Not Found"));
            }

            var ret = await DB.TestCases
                      .Select(x => new TestCaseWithContent
            {
                Id               = x.Id,
                ContestId        = x.ContestId,
                InputBlobId      = x.InputBlobId,
                InputSizeInByte  = x.InputSizeInByte,
                OutputBlobId     = x.OutputBlobId,
                OutputSizeInByte = x.OutputSizeInByte,
                ProblemId        = x.ProblemId,
                Type             = x.Type
            })
                      .SingleOrDefaultAsync(x => x.ProblemId == problemId && x.Id == id, token);

            if (ret == null)
            {
                return(Result <TestCaseWithContent>(404, "Not Found"));
            }
            else if (!await HasPermissionToProblemAsync(problemId, token) &&
                     !await DB.TestCasePurchases.AnyAsync(x => x.ProblemId == problemId && x.UserId == User.Current.Id, token))
            {
                return(Result <TestCaseWithContent>(401, "No Permission"));
            }
            else
            {
                if (showContent.HasValue && showContent.Value)
                {
                    if (await IsAbleToAccessTestCaseContentAsync(ret.ProblemId, token))
                    {
                        ret.Input  = Encoding.UTF8.GetString((await MgmtSvc.GetBlobAsync(ret.InputBlobId, token)).Body);
                        ret.Output = Encoding.UTF8.GetString((await MgmtSvc.GetBlobAsync(ret.OutputBlobId, token)).Body);
                    }
                }

                return(Result(ret));
            }
        }
Пример #4
0
        public async Task <IActionResult> Download(Guid id, [FromServices] ManagementServiceClient mgmt)
        {
            var blob = await mgmt.GetBlobAsync(id);

            if (blob.Name.StartsWith("joyoi_online_judge_upload_"))
            {
                return(File(blob.Body, "application/octet-stream", blob.Name));
            }
            else
            {
                Response.StatusCode = 404;
                return(Content("Not Found"));
            }
        }
Пример #5
0
        public async Task<IActionResult> Get(
            Guid id,
            [FromServices] ManagementServiceClient mgmt,
            [FromServices] ContestExecutorFactory cef,
            CancellationToken token)
        {
            var ret = await DB.HackStatuses
                .Include(x => x.Status)
                .Include(x => x.User)
                .SingleOrDefaultAsync(x => x.Id == id, token);

            if (IsGroupRequest() && ret.GroupId != CurrentGroup.Id)
            {
                return Result(400, "No permission");
            }

            if (ret.HackDataBlobId.HasValue)
            {
                ret.HackDataBody = Encoding.UTF8.GetString((await mgmt.GetBlobAsync(ret.HackDataBlobId.Value, token)).Body);
            }

            var username = ret.User.UserName;
            ret.User = null;

            if (ret == null)
            {
                return Result(404, "Hack status is not found");
            }

            if (!string.IsNullOrEmpty(ret.ContestId))
            {
                var ce = cef.Create(ret.ContestId);
                if ((ce.IsContestInProgress(User.Current?.UserName) || ce.IsContestInProgress(username)) && ret.UserId != User.Current?.Id && !IsMasterOrHigher && !ce.HasPermissionToContest(User.Current?.UserName))
                {
                    ce.OnShowHackResult(ret);
                }
            }

            if (User.Current?.Id != ret.UserId 
                && User.Current?.Id != ret.Status.UserId 
                && !await HasPermissionToProblemAsync(ret.Status.ProblemId, token)
                && !(IsGroupRequest() && await HasPermissionToGroupAsync(token)))
            {
                ret.HackDataBody = null;
            }

            return Result(ret);
        }
Пример #6
0
        public async Task <IActionResult> GetTestCaseOutput(
            [FromServices] ManagementServiceClient MgmtSvc,
            string problemId,
            Guid id,
            CancellationToken token)
        {
            this.HasOwnership = await HasPermissionToProblemAsync(problemId, token);

            var problem = await DB.Problems.SingleOrDefaultAsync(x => x.Id == problemId, token);

            if (problem == null || !problem.IsVisible && !this.HasOwnership)
            {
                return(Result <Problem>(404, "Not Found"));
            }

            var ret = await DB.TestCases
                      .Select(x => new TestCaseWithContent
            {
                Id               = x.Id,
                ContestId        = x.ContestId,
                InputBlobId      = x.InputBlobId,
                InputSizeInByte  = x.InputSizeInByte,
                OutputBlobId     = x.OutputBlobId,
                OutputSizeInByte = x.OutputSizeInByte,
                ProblemId        = x.ProblemId,
                Type             = x.Type
            })
                      .SingleOrDefaultAsync(x => x.ProblemId == problemId && x.Id == id, token);

            if (ret == null)
            {
                return(Result <TestCaseWithContent>(404, "Not Found"));
            }
            else if (!await HasPermissionToProblemAsync(problemId, token) &&
                     !await DB.TestCasePurchases.AnyAsync(x => x.ProblemId == problemId && x.UserId == User.Current.Id, token))
            {
                return(Result <TestCaseWithContent>(401, "No Permission"));
            }
            else
            {
                return(File((await MgmtSvc.GetBlobAsync(ret.OutputBlobId, token)).Body, "text/plain", "output.txt"));
            }
        }
Пример #7
0
        public async Task<IActionResult> GetData(
            Guid id,
            [FromServices] ManagementServiceClient mgmt,
            [FromServices] ContestExecutorFactory cef,
            CancellationToken token)
        {
            var hack = await DB.HackStatuses
                .Include(x => x.Status)
                .SingleOrDefaultAsync(x => x.Id == id);

            if (hack == null)
            {
                return Result(404, "Hack status is not found");
            }

            if (!hack.HackDataBlobId.HasValue)
            {
                return Result(404, "The hack data is not found");
            }

            if (!string.IsNullOrEmpty(hack.ContestId))
            {
                var ce = cef.Create(hack.ContestId);
                if (!IsMasterOrHigher && !await HasPermissionToProblemAsync(hack.Status.ProblemId, token) && ce.IsContestInProgress() && User.Current?.Id != hack.UserId)
                {
                    return Result(401, "No permission");
                }
            }
            else
            {
                if (!IsMasterOrHigher && !await HasPermissionToProblemAsync(hack.Status.ProblemId, token) && User.Current?.Id != hack.UserId)
                {
                    return Result(401, "No permission");
                }
            }

            var blob = await mgmt.GetBlobAsync(hack.HackDataBlobId.Value, token);
            return Result(Encoding.UTF8.GetString(blob.Body));
        }
Пример #8
0
        private async Task HandleSingleHackAsync(IEnumerable <ActorInfo> actors, HackStatus hack, JudgeStatus judge, Problem problem, Guid?testCaseId, CancellationToken token)
        {
            var sub       = new SubJudgeStatus();
            var isBadData = false;

            if (actors.Count(x => x.Name == "CompareActor") == 0)
            {
                var rangeValidateActor = actors.FirstOrDefault(x => x.Stage == "ValidateData");
                var rangeRunner        = rangeValidateActor == null ? null : await _mgmt.ReadBlobAsObjectAsync <Runner>(rangeValidateActor.Outputs.Single(x => x.Name == "runner.json").Id, token);

                var runActor  = actors.FirstOrDefault(x => x.Stage == "GenerateHackeeAnswer");
                var runRunner = runActor == null ? null : await _mgmt.ReadBlobAsObjectAsync <Runner>(runActor.Outputs.Single(x => x.Name == "runner.json").Id, token);

                if (rangeRunner != null && rangeRunner.ExitCode != 0)
                {
                    isBadData            = true;
                    sub.TimeUsedInMs     = 0;
                    sub.MemoryUsedInByte = 0;
                    sub.Result           = JudgeResult.Accepted;
                    sub.Hint             = string.Join(Environment.NewLine, rangeValidateActor.Exceptions) + Environment.NewLine + rangeRunner.Error;
                }
                else if (runRunner.IsTimeout)
                {
                    sub.TimeUsedInMs     = problem.TimeLimitationPerCaseInMs;
                    sub.MemoryUsedInByte = runRunner.PeakMemory;
                    sub.Result           = JudgeResult.TimeExceeded;
                    sub.Hint             = string.Join(Environment.NewLine, runActor.Exceptions) + Environment.NewLine + runRunner.Error;
                }
                else if (runRunner.ExitCode == 139 || runActor.Exceptions.Any(x => x.Contains("May cause by out of memory")) || runRunner.Error.Contains("std::bad_alloc") || runRunner.PeakMemory > problem.MemoryLimitationPerCaseInByte)
                {
                    sub.TimeUsedInMs     = runRunner.UserTime;
                    sub.MemoryUsedInByte = problem.MemoryLimitationPerCaseInByte;
                    sub.Result           = JudgeResult.MemoryExceeded;
                    sub.Hint             = string.Join(Environment.NewLine, runActor.Exceptions) + Environment.NewLine + runRunner.Error;
                }
                else if (runRunner.ExitCode != 0)
                {
                    sub.TimeUsedInMs     = runRunner.UserTime;
                    sub.MemoryUsedInByte = runRunner.PeakMemory;
                    sub.Result           = JudgeResult.RuntimeError;
                    sub.Hint             = string.Join(Environment.NewLine, runActor.Exceptions) + Environment.NewLine + runRunner.Error + Environment.NewLine + $"User process exited with code { runRunner.ExitCode }";
                }
            }
            else if (actors.Count(x => x.Name == "CompareActor") > 0)
            {
                var runners       = actors.Where(x => x.Name == "CompareActor").Select(x => x.Outputs.Single(y => y.Name == "runner.json"));
                var runnerResults = runners.Select(x => _mgmt.ReadBlobAsObjectAsync <Runner>(x.Id, token).Result);
                var exitCodes     = runnerResults.Select(x => x.ExitCode);
                if (exitCodes.Distinct().Count() > 1)
                {
                    isBadData = true;
                }
                else
                {
                    var runActor  = actors.First(x => x.Stage == "GenerateHackeeAnswer");
                    var runRunner = await _mgmt.ReadBlobAsObjectAsync <Runner>(runActor.Outputs.Single(x => x.Name == "runner.json").Id, token);

                    var compareActor = actors.Last(x => x.Name == "CompareActor");
                    var runner       = await _mgmt.ReadBlobAsObjectAsync <Runner>(compareActor.Outputs.Single(x => x.Name == "runner.json").Id, token);

                    if (runner.ExitCode < 0 || runner.ExitCode > 2)
                    {
                        sub.TimeUsedInMs     = 0;
                        sub.MemoryUsedInByte = 0;
                        sub.Result           = JudgeResult.SystemError;
                        sub.Hint             = string.Join(Environment.NewLine, runActor.Exceptions) + Environment.NewLine + runner.Error;
                    }
                    else
                    {
                        var validatorOutput = Encoding.UTF8.GetString((await _mgmt.GetBlobAsync(compareActor.Outputs.Single(x => x.Name == "stdout.txt").Id)).Body);
                        sub.TimeUsedInMs     = runRunner.UserTime;
                        sub.MemoryUsedInByte = runRunner.PeakMemory;
                        sub.Result           = (JudgeResult)runner.ExitCode;
                        sub.Hint             = validatorOutput + Environment.NewLine + string.Join(Environment.NewLine, runActor.Exceptions) + Environment.NewLine + runner.Error;
                    }
                }
            }
            else
            {
                isBadData = true;
            }

            if (hack == null && actors.Count(x => x.Stage == "GenerateHackeeAnswer") > 0 && testCaseId.HasValue)
            {
                var runActor = actors.First(x => x.Stage == "GenerateHackeeAnswer");
                var statusId = Guid.Parse(runActor.Tag);
                var testCase = await _db.TestCases.SingleAsync(x => x.Id == testCaseId.Value, token);

                var testCases = await _db.TestCases
                                .Where(x => x.ProblemId == problem.Id)
                                .Select(x => x.Id)
                                .ToListAsync(token);

                var status = await _db.JudgeStatuses
                             .Include(x => x.SubStatuses)
                             .SingleAsync(x => x.Id == statusId, token);

                sub.StatusId     = statusId;
                sub.TestCaseId   = testCaseId.Value;
                sub.InputBlobId  = testCase.InputBlobId;
                sub.OutputBlobId = testCase.OutputBlobId;
                sub.SubId        = testCases.IndexOf(testCaseId.Value);
                status.SubStatuses.Add(sub);
                status.MemoryUsedInByte = status.SubStatuses.Max(x => x.MemoryUsedInByte);
                status.TimeUsedInMs     = status.SubStatuses.Sum(x => x.TimeUsedInMs);
                status.Result           = status.SubStatuses.Max(x => x.Result);
                _db.SaveChanges();
            }

            if (hack != null)
            {
                _db.HackStatuses
                .Where(x => x.Id == hack.Id)
                .SetField(x => x.HackeeResult).WithValue(isBadData ? JudgeResult.Accepted : sub.Result)
                .SetField(x => x.TimeUsedInMs).WithValue(sub.TimeUsedInMs)
                .SetField(x => x.MemoryUsedInByte).WithValue(sub.MemoryUsedInByte)
                .SetField(x => x.Result).WithValue(isBadData ? (HackResult.BadData) : (sub.Result == JudgeResult.Accepted ? HackResult.Failed : HackResult.Succeeded))
                .SetField(x => x.Hint).WithValue(sub.Hint)
                .Update();
            }
        }
Пример #9
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);
            }
        }
Пример #10
0
        public async Task <IActionResult> Patch(
            string id,
            [FromServices] ManagementServiceClient MgmtSvc,
            [FromServices] StateMachineAwaiter Awaiter,
            [FromServices] IHubContext <OnlineJudgeHub> hub,
            CancellationToken token)
        {
            if (!await HasPermissionToProblemAsync(id, token))
            {
                return(Result(401, "No Permission"));
            }
            else
            {
                var problem = await DB.Problems.SingleOrDefaultAsync(x => x.Id == id, token);

                if (problem == null)
                {
                    return(Result(404, "Not Found"));
                }

                var fields = PatchEntity(problem, RequestBody);

                // Check difficulty range
                if (fields.Any(x => x == nameof(Problem.Difficulty)) && (problem.Difficulty < 0 || problem.Difficulty > 9))
                {
                    return(Result(400, "The difficulty must be 0-9."));
                }

                // Update validator
                if (fields.Any(x => x == nameof(Problem.ValidatorCode)) || fields.Any(x => x == nameof(Problem.ValidatorLanguage)))
                {
                    if (string.IsNullOrWhiteSpace(problem.ValidatorCode))
                    {
                        problem.ValidatorBlobId   = null;
                        problem.ValidatorCode     = null;
                        problem.ValidatorError    = null;
                        problem.ValidatorLanguage = null;
                    }
                    else
                    {
                        var validatorCodeId = await MgmtSvc.PutBlobAsync("validator-" + problem.Id, Encoding.UTF8.GetBytes(problem.ValidatorCode), token);

                        var stateMachineId = await MgmtSvc.PutStateMachineInstanceAsync("CompileOnlyStateMachine", Configuration["ManagementService:CallBack"], new BlobInfo[] { new BlobInfo(validatorCodeId, "Main" + Constants.GetSourceExtension(problem.ValidatorLanguage)) });

                        var result = await Awaiter.GetStateMachineResultAsync(stateMachineId, true, token);

                        var runner = JsonConvert.DeserializeObject <dynamic>(Encoding.UTF8.GetString((await MgmtSvc.GetBlobAsync(result.StartedActors.Last().Outputs.Single(x => x.Name == "runner.json").Id, token)).Body));
                        if (result.StartedActors.Any(x => x.Name == "CompileActor" && runner.ExitCode == 0 && x.Status == JoyOI.ManagementService.Model.Enums.ActorStatus.Succeeded))
                        {
                            problem.ValidatorBlobId = result.StartedActors.Last().Outputs.Single(x => x.Name.StartsWith("Main.")).Id;
                            problem.ValidatorError  = null;
                        }
                        else
                        {
                            problem.ValidatorBlobId = null;
                            problem.ValidatorError  = runner.Error;
                        }
                    }
                }

                // Update standard
                if (fields.Any(x => x == nameof(Problem.StandardCode)) || fields.Any(x => x == nameof(Problem.StandardLanguage)))
                {
                    if (string.IsNullOrWhiteSpace(problem.StandardCode))
                    {
                        problem.StandardBlobId   = null;
                        problem.StandardCode     = null;
                        problem.StandardError    = null;
                        problem.StandardLanguage = null;
                    }
                    else
                    {
                        var standardCodeId = await MgmtSvc.PutBlobAsync("standard-" + problem.Id, Encoding.UTF8.GetBytes(problem.StandardCode), token);

                        var stateMachineId = await MgmtSvc.PutStateMachineInstanceAsync("CompileOnlyStateMachine", Configuration["ManagementService:CallBack"], new BlobInfo[] { new BlobInfo(standardCodeId, "Main" + Constants.GetSourceExtension(problem.StandardLanguage)) });

                        var result = await Awaiter.GetStateMachineResultAsync(stateMachineId, true, token);

                        var runner = JsonConvert.DeserializeObject <dynamic>(Encoding.UTF8.GetString((await MgmtSvc.GetBlobAsync(result.StartedActors.Last().Outputs.Single(x => x.Name == "runner.json").Id, token)).Body));
                        if (result.StartedActors.Any(x => x.Name == "CompileActor" && runner.ExitCode == 0 && x.Status == JoyOI.ManagementService.Model.Enums.ActorStatus.Succeeded))
                        {
                            problem.StandardBlobId = result.StartedActors.Last().Outputs.Single(x => x.Name.StartsWith("Main.")).Id;
                            problem.StandardError  = null;
                        }
                        else
                        {
                            problem.StandardBlobId = null;
                            problem.StandardError  = runner.Error;
                        }
                    }
                }

                // Update range
                if (fields.Any(x => x == nameof(Problem.RangeCode)) || fields.Any(x => x == nameof(Problem.RangeLanguage)))
                {
                    if (string.IsNullOrWhiteSpace(problem.RangeCode))
                    {
                        problem.RangeBlobId   = null;
                        problem.RangeCode     = null;
                        problem.RangeError    = null;
                        problem.RangeLanguage = null;
                    }
                    else
                    {
                        var rangeCodeId = await MgmtSvc.PutBlobAsync("range-" + problem.Id, Encoding.UTF8.GetBytes(problem.RangeCode), token);

                        var stateMachineId = await MgmtSvc.PutStateMachineInstanceAsync("CompileOnlyStateMachine", Configuration["ManagementService:CallBack"], new BlobInfo[] { new BlobInfo(rangeCodeId, "Main" + Constants.GetSourceExtension(problem.RangeLanguage)) });

                        var result = await Awaiter.GetStateMachineResultAsync(stateMachineId, true, token);

                        var runner = JsonConvert.DeserializeObject <dynamic>(Encoding.UTF8.GetString((await MgmtSvc.GetBlobAsync(result.StartedActors.Last().Outputs.Single(x => x.Name == "runner.json").Id, token)).Body));
                        if (result.StartedActors.Any(x => x.Name == "CompileActor" && runner.ExitCode == 0 && x.Status == JoyOI.ManagementService.Model.Enums.ActorStatus.Succeeded))
                        {
                            problem.RangeBlobId = result.StartedActors.Last().Outputs.Single(x => x.Name.StartsWith("Main.")).Id;
                            problem.RangeError  = null;
                        }
                        else
                        {
                            problem.RangeBlobId = null;
                            problem.RangeError  = runner.Error;
                        }
                    }
                }

                if ((string.IsNullOrWhiteSpace(problem.Tags) || problem.Tags.IndexOf(LocalProblemSetTag) < 0) && problem.Source == ProblemSource.Local)
                {
                    problem.Tags += "," + LocalProblemSetTag;
                    problem.Tags  = problem.Tags.Trim(',');
                }

                await DB.SaveChangesAsync(token);

                hub.Clients.All.InvokeAsync("ItemUpdated", "problem", problem.Id);
                if (fields.Any(x => x == nameof(Problem.Title)) || fields.Any(x => x == nameof(Problem.IsVisible)))
                {
                    hub.Clients.All.InvokeAsync("ItemUpdated", "problem-list", problem.Id);
                }

                return(Result(200, "Patch Succeeded"));
            }
        }
        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();
            }
        }