Skip to content

Commit 52fde24

Browse files
author
Michael Vasseur
committed
Finish
This shows everything but still needs cleanup.
1 parent 5d5d6c6 commit 52fde24

File tree

6 files changed

+262
-26
lines changed

6 files changed

+262
-26
lines changed

judge/judgedaemon.main.php

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -889,7 +889,7 @@ function fetch_executable_internal(
889889
foreach ($row as $judgeTask) {
890890
if (isset($judgeTask['output_visualizer_script_id'])) {
891891
// Visualization of output which this host judged requested.
892-
//$run_config = dj_json_decode($judgeTask['run_config']);
892+
$run_config = dj_json_decode($judgeTask['run_config']);
893893
$tmpfile = tempnam(TMPDIR, 'output_visualization_');
894894
[$runpath, $error] = fetch_executable_internal(
895895
$workdirpath,
@@ -902,32 +902,29 @@ function fetch_executable_internal(
902902
continue;
903903
}
904904

905-
$debug_cmd = implode(' ', array_map('dj_escapeshellarg',
906-
[$runpath, $workdir, $tmpfile]));
907-
system($debug_cmd, $retval);
905+
$teamoutput = $workdir . "/testcase" . sprintf('%05d', $judgeTask['testcase_id']) . '/1/program.out';
906+
//$feedbackoutput = $wVorkdir . "/testcase" . sprintf('%05d', $judgeTask['testcase_id']) . '/1/feedback/visual.png';
907+
var_dump("Working in", $teamoutput);
908+
$visual_cmd = implode(' ', array_map('dj_escapeshellarg',
909+
[$runpath, $teamoutput, $tmpfile]));
910+
var_dump($visual_cmd);
911+
system($visual_cmd, $retval);
908912
// FIXME: check retval
913+
var_dump("testcase", $judgeTask['testcase_id']);
909914

910915
request(
911-
sprintf('judgehosts/add-debug-info/%s/%s', urlencode($myhost),
916+
sprintf('judgehosts/add-visual/%s/%s', urlencode($myhost),
912917
urlencode((string)$judgeTask['judgetaskid'])),
913918
'POST',
914-
['full_debug' => rest_encode_file($tmpfile, false)],
919+
['visual_output' => rest_encode_file($tmpfile, false),
920+
'testcase_id' => $judgeTask['testcase_id']],
915921
false
916922
);
923+
$b = rest_encode_file($tmpfile, false);
924+
var_dump($b);
917925
unlink($tmpfile);
918926

919-
logmsg(LOG_INFO, " ⇡ Uploading debug package of workdir $workdir.");
920-
} else {
921-
// Retrieving full team output for a particular testcase.
922-
$testcasedir = $workdir . "/testcase" . sprintf('%05d', $judgeTask['testcase_id']);
923-
request(
924-
sprintf('judgehosts/add-debug-info/%s/%s', urlencode($myhost),
925-
urlencode((string)$judgeTask['judgetaskid'])),
926-
'POST',
927-
['output_run' => rest_encode_file($testcasedir . '/program.out', false)],
928-
false
929-
);
930-
logmsg(LOG_INFO, " ⇡ Uploading full output of testcase $judgeTask[testcase_id].");
927+
logmsg(LOG_INFO, " ⇡ Uploading visual output of workdir $workdir.");
931928
}
932929
}
933930
continue;
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace DoctrineMigrations;
6+
7+
use Doctrine\DBAL\Schema\Schema;
8+
use Doctrine\Migrations\AbstractMigration;
9+
10+
/**
11+
* Auto-generated Migration: Please modify to your needs!
12+
*/
13+
final class Version20241017180659 extends AbstractMigration
14+
{
15+
public function getDescription(): string
16+
{
17+
return '';
18+
}
19+
20+
public function up(Schema $schema): void
21+
{
22+
// this up() migration is auto-generated, please modify it to your needs
23+
$this->addSql('CREATE TABLE visualization (visualization_id INT UNSIGNED AUTO_INCREMENT NOT NULL COMMENT \'Visualization ID\', judgingid INT UNSIGNED DEFAULT NULL COMMENT \'Judging ID\', judgehostid INT UNSIGNED DEFAULT NULL COMMENT \'Judgehost ID\', testcaseid INT UNSIGNED DEFAULT NULL COMMENT \'Testcase ID\', filename VARCHAR(255) NOT NULL COMMENT \'Name of the file where we stored the visualization.\', INDEX IDX_E0936C40E0E4FC3E (judgehostid), INDEX IDX_E0936C40D360BB2B (testcaseid), INDEX judgingid (judgingid), PRIMARY KEY(visualization_id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB COMMENT = \'Team output visualization.\' ');
24+
$this->addSql('ALTER TABLE visualization ADD CONSTRAINT FK_E0936C405D5FEA72 FOREIGN KEY (judgingid) REFERENCES judging (judgingid) ON DELETE CASCADE');
25+
$this->addSql('ALTER TABLE visualization ADD CONSTRAINT FK_E0936C40E0E4FC3E FOREIGN KEY (judgehostid) REFERENCES judgehost (judgehostid) ON DELETE SET NULL');
26+
$this->addSql('ALTER TABLE visualization ADD CONSTRAINT FK_E0936C40D360BB2B FOREIGN KEY (testcaseid) REFERENCES testcase (testcaseid) ON DELETE CASCADE');
27+
}
28+
29+
public function down(Schema $schema): void
30+
{
31+
// this down() migration is auto-generated, please modify it to your needs
32+
$this->addSql('ALTER TABLE visualization DROP FOREIGN KEY FK_E0936C405D5FEA72');
33+
$this->addSql('ALTER TABLE visualization DROP FOREIGN KEY FK_E0936C40E0E4FC3E');
34+
$this->addSql('ALTER TABLE visualization DROP FOREIGN KEY FK_E0936C40D360BB2B');
35+
$this->addSql('DROP TABLE visualization');
36+
}
37+
38+
public function isTransactional(): bool
39+
{
40+
return false;
41+
}
42+
}

webapp/src/Controller/API/JudgehostController.php

Lines changed: 61 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
namespace App\Controller\API;
44

5+
use App\Entity\Visualization;
6+
use App\Entity\Testcase;
7+
58
use App\DataTransferObject\JudgehostFile;
69
use App\Doctrine\DBAL\Types\JudgeTaskType;
710
use App\Entity\Contest;
@@ -550,6 +553,60 @@ public function addDebugInfo(
550553
$this->em->flush();
551554
}
552555

556+
/**
557+
* Add visual team output.
558+
*/
559+
#[IsGranted('ROLE_JUDGEHOST')]
560+
#[Rest\Post('/add-visual/{hostname}/{judgeTaskId<\d+>}')]
561+
#[OA\Response(response: 200, description: 'When the visual output has been added')]
562+
public function addVisualization(
563+
Request $request,
564+
#[OA\PathParameter(description: 'The hostname of the judgehost that wants to add the debug info')]
565+
string $hostname,
566+
#[OA\PathParameter(description: 'The ID of the judgetask to add', schema: new OA\Schema(type: 'integer'))]
567+
int $judgeTaskId
568+
): void {
569+
$judgeTask = $this->em->getRepository(JudgeTask::class)->find($judgeTaskId);
570+
if ($judgeTask === null) {
571+
throw new BadRequestHttpException(
572+
'Inconsistent data, no judgetask known with judgetaskid = ' . $judgeTaskId . '.');
573+
}
574+
575+
foreach (['visual_output', 'testcase_id'] as $argument) {
576+
if (!$request->request->has($argument)) {
577+
throw new BadRequestHttpException(
578+
sprintf("Argument '%s' is mandatory", $argument));
579+
}
580+
}
581+
582+
$judgehost = $this->em->getRepository(Judgehost::class)->findOneBy(['hostname' => $hostname]);
583+
if (!$judgehost) {
584+
throw new BadRequestHttpException("Who are you and why are you sending us any data?");
585+
}
586+
587+
$judging = $this->em->getRepository(Judging::class)->find($judgeTask->getJobId());
588+
if ($judging === null) {
589+
throw new BadRequestHttpException(
590+
'Inconsistent data, no judging known with judgingid = ' . $judgeTask->getJobId() . '.');
591+
}
592+
if ($tempFilename = tempnam($this->dj->getDomjudgeTmpDir(), "visual-")) {
593+
$debug_package = base64_decode($request->request->get('visual_output'));
594+
file_put_contents($tempFilename, $debug_package);
595+
var_dump($debug_package);
596+
}
597+
// FIXME: error checking
598+
var_dump("Received", $request->request->get('testcase_id'), "Processed" );
599+
$testcase = $this->em->getRepository(Testcase::class)->findOneBy(['testcaseid' => $request->request->get('testcase_id')]);
600+
$visualization = new Visualization();
601+
$visualization
602+
->setJudgehost($judgehost)
603+
->setJudging($judging)
604+
->setTestcase($testcase)
605+
->setFilename($tempFilename);
606+
$this->em->persist($visualization);
607+
$this->em->flush();
608+
}
609+
553610
/**
554611
* Add one JudgingRun. When relevant, finalize the judging.
555612
* @throws DBALException
@@ -1186,7 +1243,7 @@ public function getFilesAction(
11861243
return match ($type) {
11871244
'source' => $this->getSourceFiles($id),
11881245
'testcase' => $this->getTestcaseFiles($id),
1189-
'compare', 'compile', 'debug', 'run' => $this->getExecutableFiles($id),
1246+
'compare', 'compile', 'debug', 'run', 'output_visualization' => $this->getExecutableFiles($id),
11901247
default => throw new BadRequestHttpException('Unknown type requested.'),
11911248
};
11921249
}
@@ -1656,7 +1713,7 @@ public function getJudgeTasksAction(Request $request): array
16561713
->createQueryBuilder()
16571714
->from(JudgeTask::class, 'jt')
16581715
->select('jt')
1659-
->andWhere('jt.judgehost = :judgehost')
1716+
->andWhere('jt.judgehost = :judgehost OR jt.judgehost IS NULL')
16601717
//->andWhere('jt.starttime IS NULL')
16611718
->andWhere('jt.valid = 1')
16621719
->andWhere('jt.type = :type')
@@ -1703,7 +1760,7 @@ private function serializeJudgeTasks(array $judgeTasks, Judgehost $judgehost): a
17031760
}
17041761

17051762
$now = Utils::now();
1706-
$numUpdated = $this->em->getConnection()->executeStatement(
1763+
$numUpdated = sizeof($judgeTasks);/*$this->em->getConnection()->executeStatement(
17071764
'UPDATE judgetask SET judgehostid = :judgehostid, starttime = :starttime WHERE starttime IS NULL AND valid = 1 AND judgetaskid IN (:ids)',
17081765
[
17091766
'judgehostid' => $judgehost->getJudgehostid(),
@@ -1718,7 +1775,7 @@ private function serializeJudgeTasks(array $judgeTasks, Judgehost $judgehost): a
17181775
if ($numUpdated == 0) {
17191776
// Bad luck, some other judgehost beat us to it.
17201777
return [];
1721-
}
1778+
}*/
17221779

17231780
// We got at least one, let's update the starttime of the corresponding judging if haven't done so in the past.
17241781
$starttime_set = $this->em->getConnection()->executeStatement(

webapp/src/Controller/Jury/SubmissionController.php

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,14 @@
1616
use App\Entity\JudgingRun;
1717
use App\Entity\Language;
1818
use App\Entity\Problem;
19+
use App\Entity\QueueTask;
1920
use App\Entity\Submission;
2021
use App\Entity\SubmissionFile;
2122
use App\Entity\Team;
2223
use App\Entity\TeamAffiliation;
2324
use App\Entity\TeamCategory;
2425
use App\Entity\Testcase;
25-
use App\Entity\QueueTask;
26+
use App\Entity\Visualization;
2627
use App\Form\Type\SubmissionsFilterType;
2728
use App\Service\BalloonService;
2829
use App\Service\ConfigurationService;
@@ -513,6 +514,14 @@ public function viewAction(
513514
->getSingleScalarResult();
514515
}
515516

517+
$visualization = null;
518+
$createdVisualization = $this->em->getRepository(Visualization::class)->findOneBy([
519+
'judging' => $selectedJudging,
520+
]);
521+
if ($createdVisualization) {
522+
$visualization = ['url' => $this->generateUrl('jury_submission_visual', ['visualId' => $createdVisualization->getVisualizationId()])];
523+
}
524+
516525
$twigData = [
517526
'submission' => $submission,
518527
'lastSubmission' => $lastSubmission,
@@ -536,6 +545,7 @@ public function viewAction(
536545
'version_warnings' => [],
537546
'isMultiPassProblem' => $submission->getProblem()->isMultipassProblem(),
538547
'hasOutputVisualizer' => $submission->getProblem()->getOutputVisualizerExecutable() ?? false,
548+
'visualization' => $visualization,
539549
];
540550

541551
if ($selectedJudging === null) {
@@ -1385,6 +1395,7 @@ protected function createVisualization(array $judgings): void
13851395
// We need to get the Judging_run first.
13861396
//->setJudgehost($judging->getJudgeTask()->getJudgehost())
13871397
->setSubmission($submission)
1398+
->setTestcaseId($run->getTestcase()->getTestcaseId())
13881399
->setPriority(JudgeTask::PRIORITY_LOW)
13891400
->setOutputVisualizerScriptId($executable->getImmutableExecId())
13901401
->setRunConfig($this->dj->jsonEncode(['hash' => $executable->getHash()]));
@@ -1417,4 +1428,18 @@ protected function createVisualization(array $judgings): void
14171428
$this->addFlash('info', "Requested $numRequested to be visualized.");
14181429
}
14191430
}
1431+
1432+
#[Route(path: '/visual/{visualId}', name: 'jury_submission_visual')]
1433+
public function visualAction(
1434+
Request $request,
1435+
?string $visualId = null,
1436+
): StreamedResponse {
1437+
1438+
dump($visualId);
1439+
$visualization = $this->em->getRepository(Visualization::class)->findOneBy(['visualization_id' => $visualId]);
1440+
dump($visualization, $visualId);
1441+
$name = 'visual.j' . $visualization->getJudging()->getJudgingid()
1442+
. '.png';
1443+
return Utils::streamAsBinaryFile(file_get_contents($visualization->getFilename()), $name);
1444+
}
14201445
}

0 commit comments

Comments
 (0)