Skip to content
Snippets Groups Projects
StartTaskCreateResultAction.php 4.96 KiB
Newer Older
  • Learn to ignore specific revisions
  • François Agneray's avatar
    François Agneray committed
    <?php
    
    /*
     * This file is part of Anis Server.
     *
     * (c) Laboratoire d'Astrophysique de Marseille / CNRS
     *
     * For the full copyright and license information, please view the LICENSE
     * file that was distributed with this source code.
     */
    declare(strict_types=1);
    
    namespace App\Action;
    
    
    use Psr\Http\Message\ServerRequestInterface;
    use Psr\Http\Message\ResponseInterface;
    
    François Agneray's avatar
    François Agneray committed
    use Slim\Exception\HttpBadRequestException;
    use Slim\Exception\HttpNotFoundException;
    use Doctrine\ORM\EntityManagerInterface;
    
    use PhpAmqpLib\Connection\AbstractConnection;
    
    François Agneray's avatar
    François Agneray committed
    use PhpAmqpLib\Message\AMQPMessage;
    
    François Agneray's avatar
    François Agneray committed
    
    /**
     * @author François Agneray <francois.agneray@lam.fr>
     * @package App\Action
     */
    
    final class StartTaskCreateResultAction extends AbstractAction
    
    François Agneray's avatar
    François Agneray committed
    {
        /**
    
         * Contains RabbitMQ connection socket
    
    François Agneray's avatar
    François Agneray committed
         *
    
         * @var AbstractConnection
    
    François Agneray's avatar
    François Agneray committed
         */
    
    François Agneray's avatar
    François Agneray committed
    
        /**
         * Contains settings to handle Json Web Token (app/settings.php)
         *
         * @var array
         */
        private $settings;
    
        /**
         * Create the classe before call __invoke to execute the action
         *
    
         * @param EntityManagerInterface $em       Doctrine Entity Manager Interface
         * @param AbstractConnection     $rmq      RabbitMQ connection socket
         * @param array                  $settings Settings about token
    
    François Agneray's avatar
    François Agneray committed
         */
        public function __construct(
            EntityManagerInterface $em,
    
            AbstractConnection $rmq,
    
    François Agneray's avatar
    François Agneray committed
            array $settings
        ) {
            parent::__construct($em);
    
    François Agneray's avatar
    François Agneray committed
            $this->settings = $settings;
        }
    
        /**
    
         * `GET` Starts an asynchronous task, through rabbitmq, to build an archive
    
    François Agneray's avatar
    François Agneray committed
         *
         * @param  ServerRequestInterface $request  PSR-7 This object represents the HTTP request
         * @param  ResponseInterface      $response PSR-7 This object represents the HTTP response
         * @param  string[]               $args     This table contains information transmitted in the URL (see routes.php)
         *
         * @return ResponseInterface
         */
    
        public function __invoke(
            ServerRequestInterface $request,
            ResponseInterface $response,
            array $args
        ): ResponseInterface {
    
    François Agneray's avatar
    François Agneray committed
            if ($request->getMethod() === OPTIONS) {
                return $response->withHeader('Access-Control-Allow-Methods', 'GET, OPTIONS');
            }
    
            // Search the correct dataset with primary key
            $datasetName = $args['dname'];
            $dataset = $this->em->find('App\Entity\Dataset', $datasetName);
    
            // If dataset is not found 404
            if (is_null($dataset)) {
                throw new HttpNotFoundException(
                    $request,
                    'Dataset with name ' . $datasetName . ' is not found'
                );
            }
    
    
    François Agneray's avatar
    François Agneray committed
    
            // If instance is private and authorization enabled
            $instance = $dataset->getDatasetFamily()->getInstance();
            if (!$instance->getPublic() && boolval($this->settings['enabled'])) {
                $this->verifyInstanceAuthorization(
                    $request,
                    $instance->getName(),
                    explode(',', $this->settings['admin_roles'])
                );
                $token = $request->getHeader('Authorization')[0];
            }
    
            // If dataset is private and authorization enabled
    
    François Agneray's avatar
    François Agneray committed
            if (!$dataset->getPublic() && boolval($this->settings['enabled'])) {
    
    François Agneray's avatar
    François Agneray committed
                $this->verifyDatasetAuthorization(
                    $request,
                    $dataset->getName(),
                    explode(',', $this->settings['admin_roles'])
                );
    
                $token = $request->getHeader('Authorization')[0];
    
    François Agneray's avatar
    François Agneray committed
            }
    
    François Agneray's avatar
    François Agneray committed
            
    
    François Agneray's avatar
    François Agneray committed
            $queryParams = $request->getQueryParams();
    
            // The parameter "a" is mandatory
            if (!array_key_exists('a', $queryParams)) {
                throw new HttpBadRequestException(
                    $request,
                    'Param a is required for this request'
                );
            }
    
    
            // Search extension
    
            if ($queryParams['f'] === 'csv') {
    
                $extension = '.csv';
    
    François Agneray's avatar
    François Agneray committed
            } elseif ($queryParams['f'] === 'ascii') {
    
                $extension = '.txt';
    
    François Agneray's avatar
    François Agneray committed
            } elseif ($queryParams['f'] === 'votable') {
    
                $extension = '.xml';
            } else {
                $extension = '.json';
            }
    
    
            // Create the name of the future archive
    
            $fileName = 'result_' . $dataset->getName() . '_' . (new \DateTime())->format('Y-m-d\TH:i:s') . $extension;
    
            $fileId = uniqid();
    
            // Publish message in the archive queue
            $channel = $this->rmq->channel();
    
    François Agneray's avatar
    François Agneray committed
            $channel->queue_declare('archive', false, false, false, false);
    
    François Agneray's avatar
    François Agneray committed
            $msg = new AMQPMessage(json_encode(array(
    
                'file_id' => $fileId,
    
    François Agneray's avatar
    François Agneray committed
                'dataset_name' => $datasetName,
    
                'query' => $request->getUri()->getQuery(),
                'token' => $token
    
    François Agneray's avatar
    François Agneray committed
            )));
    
            $channel->basic_publish($msg, '', 'result');
    
            // Just returns the future archive name
    
            $payload = json_encode(array('file_name' => $fileName, 'file_id' => $fileId));
    
            $response->getBody()->write($payload);
            return $response;