public async Task <IActionResult> Put( [FromServices] IConfiguration Config, [FromServices] IServiceScopeFactory scopeFactory, [FromServices] StateMachineAwaiter awaiter, [FromServices] ManagementServiceClient MgmtSvc, [FromServices] IHubContext <OnlineJudgeHub> hub, [FromServices] ContestExecutorFactory cef, CancellationToken token) { var request = JsonConvert.DeserializeObject <JudgeRequest>(RequestBody); var problem = await DB.Problems .Include(x => x.TestCases) .SingleOrDefaultAsync(x => x.Id == request.problemId, token); if (problem == null) { return(Result(400, "The problem is not exist.")); } if (!problem.IsVisible && string.IsNullOrWhiteSpace(request.contestId) && !await HasPermissionToProblemAsync(problem.Id, token)) { return(Result(403, "You have no permission to the problem.")); } if (IsGroupRequest() && !await IsGroupMemberAsync(token)) { return(Result(401, "You are not a member of this group.")); } if (!Constants.SupportedLanguages.Contains(request.language)) { return(Result(400, "The language has not been supported.")); } if (string.IsNullOrEmpty(request.code)) { return(Result(400, "Code could not be empty.")); } if (!string.IsNullOrEmpty(request.contestId)) { var ce = cef.Create(request.contestId); if (!ce.IsContestInProgress(User.Current?.UserName)) { return(Result(400, "The contest is inactive.")); } if (request.isSelfTest) { return(Result(400, "You could not do a self test during the contest is in progress.")); } if (await DB.ContestProblemLastStatuses.AnyAsync(x => x.IsLocked && x.ContestId == request.contestId && User.Current.Id == x.UserId && x.ProblemId == request.problemId, token)) { return(Result(400, "You have locked this problem.")); } } if (!Constants.SupportedLanguages.Contains(request.language) && !Constants.UnsupportedLanguages.Contains(request.language) && problem.Source == ProblemSource.Local) { return(Result(400, "The programming language which you selected was not supported")); } if (request.isSelfTest && request.data.Count() == 0) { return(Result(400, "The self testing data has not been found")); } if (problem.Source != ProblemSource.Local && request.isSelfTest) { return(Result(400, "You could not use self data to test with a remote problem.")); } if (IsGroupRequest() && !await DB.GroupProblems.AnyAsync(x => x.ProblemId == problem.Id && x.GroupId == CurrentGroup.Id) && string.IsNullOrEmpty(request.contestId)) { return(Result(404, "The problem does not exist.")); } #region Local Judge if (problem.Source == ProblemSource.Local) { var blobs = new ConcurrentDictionary <int, BlobInfo[]>(); blobs.TryAdd(-1, new[] { new BlobInfo { Id = await MgmtSvc.PutBlobAsync("Main" + Constants.GetSourceExtension(request.language), Encoding.UTF8.GetBytes(request.code)), Name = "Main" + Constants.GetSourceExtension(request.language), Tag = "Problem=" + problem.Id } }); blobs.TryAdd(-2, new[] { new BlobInfo { Id = await MgmtSvc.PutBlobAsync("limit.json", Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(new { UserTime = problem.TimeLimitationPerCaseInMs, PhysicalTime = problem.TimeLimitationPerCaseInMs * 4, Memory = problem.MemoryLimitationPerCaseInByte }))), Name = "limit.json", Tag = "Problem=" + problem.Id } }); if (!problem.ValidatorBlobId.HasValue) { blobs.TryAdd(-3, new[] { new BlobInfo { Id = Guid.Parse(Config["JoyOI:StandardValidatorBlobId"]), Name = "Validator.out" } }); } else { blobs.TryAdd(-3, new[] { new BlobInfo { Id = problem.ValidatorBlobId.Value, Name = "Validator" + Constants.GetBinaryExtension(problem.ValidatorLanguage) } }); } List <TestCase> testCases = null; if (request.isSelfTest) { Parallel.For(0, request.data.Count(), i => { // Uploading custom data var inputId = MgmtSvc.PutBlobAsync($"input_{ i }.txt", Encoding.UTF8.GetBytes(request.data.ElementAt(i).input), token).Result; var outputId = MgmtSvc.PutBlobAsync($"output_{ i }.txt", Encoding.UTF8.GetBytes(request.data.ElementAt(i).output), token).Result; blobs.TryAdd(i, new[] { new BlobInfo { Id = inputId, Name = $"input_{ i }.txt", Tag = i.ToString() }, new BlobInfo { Id = outputId, Name = $"output_{ i }.txt", Tag = i.ToString() } }); }); } else { testCases = await DB.TestCases .Where(x => x.ProblemId == problem.Id && (x.Type == TestCaseType.Small || x.Type == TestCaseType.Large || x.Type == TestCaseType.Hack)) .ToListAsync(token); if (testCases.Count == 0) { return(Result(400, "No test case found.")); } for (var i = 0; i < testCases.Count; i++) { blobs.TryAdd(i, new[] { new BlobInfo { Id = testCases[i].InputBlobId, Name = $"input_{ i }.txt", Tag = i.ToString() }, new BlobInfo { Id = testCases[i].OutputBlobId, Name = $"output_{ i }.txt", Tag = i.ToString() } }); } } var stateMachineId = await MgmtSvc.PutStateMachineInstanceAsync("JudgeStateMachine", Config["ManagementService:CallBack"], blobs.SelectMany(x => x.Value), await CalculatePriorityAsync(), token); var substatuses = blobs .Where(x => x.Key >= 0) .Select(x => new SubJudgeStatus { SubId = x.Key, Result = JudgeResult.Pending, InputBlobId = x.Value.Single(y => y.Name.StartsWith("input_")).Id, OutputBlobId = x.Value.Single(y => y.Name.StartsWith("output_")).Id, TestCaseId = testCases != null ? (Guid?)testCases[x.Key].Id : null }) .ToList(); var status = new JudgeStatus { Code = request.code, Language = request.language, Result = JudgeResult.Pending, CreatedTime = DateTime.UtcNow, ContestId = request.contestId, SubStatuses = substatuses, ProblemId = problem.Id, UserId = User.Current.Id, IsSelfTest = request.isSelfTest, RelatedStateMachineIds = new List <JudgeStatusStateMachine> { new JudgeStatusStateMachine { StateMachine = new StateMachine { CreatedTime = DateTime.UtcNow, Name = "JudgeStateMachine", Id = stateMachineId }, StateMachineId = stateMachineId } }, }; if (IsGroupRequest()) { status.GroupId = CurrentGroup.Id; } DB.JudgeStatuses.Add(status); await DB.SaveChangesAsync(token); hub.Clients.All.InvokeAsync("ItemUpdated", "judge", status.Id); // For debugging if (Config["ManagementService:Mode"] == "Polling") { Task.Factory.StartNew(async() => { using (var scope = scopeFactory.CreateScope()) using (var db = scope.ServiceProvider.GetService <OnlineJudgeContext>()) { try { await awaiter.GetStateMachineResultAsync(stateMachineId); var handler = scope.ServiceProvider.GetService <JudgeStateMachineHandler>(); await handler.HandleJudgeResultAsync(stateMachineId, default(CancellationToken)); } catch (Exception ex) { Console.Error.WriteLine(ex); } } }); } return(Result(status.Id)); } #endregion #region Bzoj, LeetCode, CodeVS else if (problem.Source == ProblemSource.Bzoj || problem.Source == ProblemSource.LeetCode || problem.Source == ProblemSource.CodeVS) { var metadata = new { Source = problem.Source.ToString(), Language = request.language, Code = request.code, ProblemId = problem.Id.Replace(problem.Source.ToString().ToLower() + "-", "") }; var metadataBlob = new BlobInfo { Id = await MgmtSvc.PutBlobAsync("metadata.json", Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(metadata)), token), Name = "metadata.json", Tag = "Problem=" + problem.Id }; var stateMachineId = await MgmtSvc.PutStateMachineInstanceAsync("VirtualJudgeStateMachine", Config["ManagementService:Callback"], new[] { metadataBlob }, await CalculatePriorityAsync(), token); var status = new JudgeStatus { Code = request.code, ContestId = request.contestId, Language = request.language, ProblemId = problem.Id, IsSelfTest = false, UserId = User.Current.Id, Result = JudgeResult.Pending, RelatedStateMachineIds = new List <JudgeStatusStateMachine> { new JudgeStatusStateMachine { StateMachine = new StateMachine { CreatedTime = DateTime.UtcNow, Name = "JudgeStateMachine", Id = stateMachineId }, StateMachineId = stateMachineId } } }; if (IsGroupRequest()) { status.GroupId = CurrentGroup.Id; } DB.JudgeStatuses.Add(status); await DB.SaveChangesAsync(token); // For debugging if (Config["ManagementService:Mode"] == "Polling") { Task.Factory.StartNew(async() => { using (var scope = scopeFactory.CreateScope()) { try { await awaiter.GetStateMachineResultAsync(stateMachineId); var handler = scope.ServiceProvider.GetService <JudgeStateMachineHandler>(); await handler.HandleJudgeResultAsync(stateMachineId, default(CancellationToken)); } catch (Exception ex) { Console.Error.WriteLine(ex); } } }); } hub.Clients.All.InvokeAsync("ItemUpdated", "judge", status.Id); return(Result(status.Id)); } #endregion #region Others else { throw new NotSupportedException(problem.Source.ToString() + " has not been supported yet."); } #endregion }
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")); } }