Skip to content

Commit a441712

Browse files
authored
Merge pull request #1754 from hashtopolis/1747-bug-helper-for-generating-an-image-for-the-visual-graph
Added helper endpoint to generate image of the progress of a task
2 parents 47045bd + 0c57922 commit a441712

File tree

2 files changed

+229
-1
lines changed

2 files changed

+229
-1
lines changed

composer.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,10 @@
4444
"phpstan/extension-installer": true
4545
},
4646
"process-timeout": 0,
47-
"sort-packages": true
47+
"sort-packages": true,
48+
"audit": {
49+
"block-insecure": false
50+
}
4851
},
4952
"autoload": {
5053
"psr-4": {
Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
<?php
2+
3+
use DBA\Chunk;
4+
use JetBrains\PhpStorm\NoReturn;
5+
use Psr\Http\Message\ResponseInterface as Response;
6+
use Psr\Http\Message\ServerRequestInterface as Request;
7+
use DBA\Factory;
8+
use DBA\OrderFilter;
9+
use DBA\QueryFilter;
10+
use DBA\Task;
11+
use Middlewares\Utils\HttpErrorException;
12+
use Slim\Exception\HttpNotFoundException;
13+
14+
require_once(dirname(__FILE__) . "/../common/AbstractHelperAPI.class.php");
15+
16+
class GetTaskProgressImageHelperAPI extends AbstractHelperAPI {
17+
public static function getBaseUri(): string {
18+
return "/api/v2/helper/getTaskProgressImage";
19+
}
20+
21+
public static function getAvailableMethods(): array {
22+
return ['GET'];
23+
}
24+
25+
public function getRequiredPermissions(string $method): array {
26+
return [Task::PERM_READ];
27+
}
28+
29+
/**
30+
* getfile is different because it returns actual binary data.
31+
*/
32+
public static function getResponse(): null {
33+
return null;
34+
}
35+
36+
37+
#[NoReturn] public function actionPost(array $data): object|array|null {
38+
assert(False, "GetTaskProgressImage has no POST");
39+
}
40+
41+
/**
42+
* Description of get params for swagger.
43+
*/
44+
public function getParamsSwagger(): array {
45+
return [
46+
[
47+
"in" => "query",
48+
"name" => "supertask",
49+
"schema" => [
50+
"type" => "integer",
51+
"format" => "int32"
52+
],
53+
"required" => false,
54+
"example" => 1,
55+
"description" => "The ID of the supertask where you want to create the progress image of."
56+
],
57+
[
58+
"in" => "query",
59+
"name" => "task",
60+
"schema" => [
61+
"type" => "integer",
62+
"format" => "int32"
63+
],
64+
"required" => false,
65+
"example" => 1,
66+
"description" => "The ID of the task where you want to create the progress image of."
67+
]
68+
];
69+
}
70+
71+
/**
72+
* Endpoint to download files
73+
* @param Request $request
74+
* @param Response $response
75+
* @return Response
76+
* @throws HTException
77+
* @throws HttpErrorException
78+
* @throws HttpForbidden
79+
*/
80+
public function handleGet(Request $request, Response $response): Response {
81+
$this->preCommon($request);
82+
$task_id = $request->getQueryParams()['task'];
83+
$supertask_id = $request->getQueryParams()['supertask'];
84+
85+
//check if task exists and get information
86+
if ($task_id) {
87+
$task = Factory::getTaskFactory()->get($task_id);
88+
if ($task == null) {
89+
throw new HttpNotFoundException($request, "Invalid task");
90+
}
91+
$taskWrapper = Factory::getTaskWrapperFactory()->get($task->getTaskWrapperId());
92+
if ($taskWrapper == null) {
93+
throw new HttpError("Inconsistency on task!");
94+
}
95+
}
96+
else if ($supertask_id) {
97+
$taskWrapper = Factory::getTaskWrapperFactory()->get($supertask_id);
98+
if ($taskWrapper == null) {
99+
throw new HttpError("Invalid task wrapper!");
100+
}
101+
} else {
102+
throw new HttpError("No task or super task has been provided");
103+
}
104+
105+
$size = array(1500, 32);
106+
107+
//create image
108+
$image = imagecreatetruecolor($size[0], $size[1]);
109+
imagesavealpha($image, true);
110+
111+
//set colors
112+
$transparency = imagecolorallocatealpha($image, 0, 0, 0, 127);
113+
$yellow = imagecolorallocate($image, 255, 255, 0);
114+
$red = imagecolorallocate($image, 255, 0, 0);
115+
$grey = imagecolorallocate($image, 192, 192, 192);
116+
$green = imagecolorallocate($image, 0, 255, 0);
117+
$blue = imagecolorallocate($image, 60, 60, 245);
118+
119+
//prepare image
120+
imagefill($image, 0, 0, $transparency);
121+
122+
if ($taskWrapper->getTaskType() == DTaskTypes::SUPERTASK && isset($supertask_id)) {
123+
// handle supertask progress drawing here
124+
$qF = new QueryFilter(Task::TASK_WRAPPER_ID, $taskWrapper->getId(), "=");
125+
$oF = new OrderFilter(Task::PRIORITY, "DESC");
126+
$tasks = Factory::getTaskFactory()->filter([Factory::FILTER => $qF, Factory::ORDER => $oF]);
127+
$numTasks = sizeof($tasks);
128+
for ($i = 0; $i < sizeof($tasks); $i++) {
129+
$qF = new QueryFilter(Chunk::TASK_ID, $tasks[$i]->getId(), "=");
130+
$chunks = Factory::getChunkFactory()->filter([Factory::FILTER => $qF]);
131+
$progress = 0;
132+
foreach ($chunks as $chunk) {
133+
$progress += $chunk->getCheckpoint();
134+
}
135+
$qF = new QueryFilter(Chunk::TASK_ID, $tasks[$i]->getId(), "=");
136+
$chunks = Factory::getChunkFactory()->filter([Factory::FILTER => $qF]);
137+
$cracked = 0;
138+
foreach ($chunks as $chunk) {
139+
$cracked += $chunk->getCracked();
140+
}
141+
if ($cracked > 0) {
142+
imagefilledrectangle($image, $i * $size[0] / $numTasks, 0, ($i + 1) * $size[0] / $numTasks, $size[1] - 1, $green);
143+
}
144+
else if ($tasks[$i]->getKeyspace() > 0 && $progress >= $tasks[$i]->getKeyspace()) {
145+
imagefilledrectangle($image, $i * $size[0] / $numTasks, 0, ($i + 1) * $size[0] / $numTasks, $size[1] - 1, $blue);
146+
}
147+
else if ($tasks[$i]->getKeyspace() > 0 && $progress > 0) {
148+
imagefilledrectangle($image, $i * $size[0] / $numTasks, 0, ($i + 1) * $size[0] / $numTasks, $size[1] - 1, $yellow);
149+
}
150+
else {
151+
imagefilledrectangle($image, $i * $size[0] / $numTasks, 0, ($i + 1) * $size[0] / $numTasks, $size[1] - 1, $grey);
152+
}
153+
}
154+
}
155+
else {
156+
$progress = $task->getKeyspaceProgress();
157+
$keyspace = max($task->getKeyspace(), 1);
158+
159+
//load chunks
160+
$qF = new QueryFilter(Task::TASK_ID, $task->getId(), "=");
161+
$chunks = Factory::getChunkFactory()->filter([Factory::FILTER => $qF]);
162+
foreach ($chunks as $chunk) {
163+
if ($task->getUsePreprocessor() == 1 && $task->getKeyspace() <= 0) {
164+
continue;
165+
}
166+
$start = floor(($size[0] - 1) * $chunk->getSkip() / $keyspace);
167+
$end = floor(($size[0] - 1) * ($chunk->getSkip() + $chunk->getLength()) / $keyspace) - 1;
168+
//division by 10000 is required because rprogress is saved in percents with two decimals
169+
$current = floor(($size[0] - 1) * ($chunk->getSkip() + $chunk->getLength() * $chunk->getProgress() / 10000) / $keyspace) - 1;
170+
171+
if ($current > $end) {
172+
$current = $end;
173+
}
174+
175+
if ($end - $start < 3) {
176+
if ($chunk->getState() >= 6) {
177+
imagefilledrectangle($image, $start, 0, $end, $size[1] - 1, $red);
178+
}
179+
else if ($chunk->getCracked() > 0) {
180+
imagefilledrectangle($image, $start, 0, $end, $size[1] - 1, $green);
181+
}
182+
else {
183+
imagefilledrectangle($image, $start, 0, $end, $size[1] - 1, $yellow);
184+
}
185+
}
186+
else {
187+
if ($chunk->getState() >= 6) {
188+
imagerectangle($image, $start, 0, $end, ($size[1] - 1), $red);
189+
}
190+
else {
191+
imagerectangle($image, $start, 0, $end, ($size[1] - 1), $grey);
192+
}
193+
if ($chunk->getCracked() > 0) {
194+
imagefilledrectangle($image, $start + 1, 1, $current - 1, $size[1] - 2, $green);
195+
}
196+
else {
197+
imagefilledrectangle($image, $start + 1, 1, $current - 1, $size[1] - 2, $yellow);
198+
}
199+
}
200+
}
201+
}
202+
203+
//send image data to output
204+
ob_start();
205+
imagepng($image);
206+
$imageData = ob_get_clean();
207+
imagedestroy($image);
208+
$response->getBody()->write($imageData);
209+
return $response->withStatus(200)
210+
->withHeader("Content-Type", "image/png")
211+
->withHeader("Cache-Control", "no-cache");
212+
}
213+
214+
static public function register($app): void {
215+
$baseUri = GetTaskProgressImageHelperAPI::getBaseUri();
216+
217+
/* Allow CORS preflight requests */
218+
$app->options($baseUri, function (Request $request, Response $response): Response {
219+
return $response;
220+
});
221+
$app->get($baseUri, "GetTaskProgressImageHelperAPI:handleGet");
222+
}
223+
}
224+
225+
GetTaskProgressImageHelperAPI::register($app);

0 commit comments

Comments
 (0)