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