StressSubscribersCommand::configure()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 6
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 8
ccs 0
cts 7
cp 0
crap 2
rs 10
1
<?php
2
3
namespace BenTools\MercurePHP\Command;
4
5
use Lcobucci\JWT\Builder;
6
use Lcobucci\JWT\Signer\Hmac\Sha256;
7
use Lcobucci\JWT\Signer\Key;
8
use RingCentral\Psr7\Uri;
9
use Symfony\Component\Console\Command\Command;
10
use Symfony\Component\Console\Input\InputArgument;
11
use Symfony\Component\Console\Input\InputInterface;
12
use Symfony\Component\Console\Input\InputOption;
13
use Symfony\Component\Console\Output\OutputInterface;
14
use Symfony\Component\Console\Style\SymfonyStyle;
15
use Symfony\Component\HttpClient\Exception\TimeoutException;
16
use Symfony\Component\HttpClient\Exception\TransportException;
17
use Symfony\Component\HttpClient\HttpClient;
18
use Symfony\Contracts\HttpClient\HttpClientInterface;
19
20
final class StressSubscribersCommand extends Command
21
{
22
    protected static $defaultName = 'mercure:stress:subscribers';
23
24
    protected function execute(InputInterface $input, OutputInterface $output): int
25
    {
26
        $output = new SymfonyStyle($input, $output);
27
        $start = time();
28
29
        if (null === $input->getOption('jwt-key')) {
30
            $output->error('No jwt-key provided.');
31
32
            return 1;
33
        }
34
35
        if (null === $input->getOption('topics')) {
36
            $output->error('No topics provided.');
37
38
            return 1;
39
        }
40
41
        $jwt = (new Builder())
42
            ->withClaim('mercure', ['subscribe' => ['*']])
43
            ->getToken(new Sha256(), new Key($input->getOption('jwt-key')));
0 ignored issues
show
Bug introduced by
It seems like $input->getOption('jwt-key') can also be of type string[]; however, parameter $content of Lcobucci\JWT\Signer\Key::__construct() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

43
            ->getToken(new Sha256(), new Key(/** @scrutinizer ignore-type */ $input->getOption('jwt-key')));
Loading history...
44
45
        $client = HttpClient::create(
46
            [
47
                'http_version' => '2.0',
48
                'verify_peer' => false,
49
                'verify_host' => false,
50
                'headers' => [
51
                    'Authorization' => 'Bearer ' . $jwt,
52
                ],
53
            ]
54
        );
55
56
        $url = new Uri($input->getArgument('url'));
0 ignored issues
show
Bug introduced by
It seems like $input->getArgument('url') can also be of type string[]; however, parameter $uri of RingCentral\Psr7\Uri::__construct() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

56
        $url = new Uri(/** @scrutinizer ignore-type */ $input->getArgument('url'));
Loading history...
57
        $qs = '';
58
        $topics = \explode(',', $input->getOption('topics'));
59
        foreach ($topics as $topic) {
60
            $qs .= '&topic=' . $topic;
61
        }
62
63
        $url = $url->withQuery($qs);
64
        $nbSubscribers = (int) $input->getOption('subscribers');
65
66
        $requests = function (HttpClientInterface $client, string $url) use ($nbSubscribers) {
67
            for ($i = 0; $i < $nbSubscribers; $i++) {
68
                yield $client->request('GET', $url);
69
            }
70
        };
71
72
        $duration = (int) $input->getOption('duration');
73
        $times = [];
74
        try {
75
            foreach ($client->stream($requests($client, $url), $duration) as $response => $chunk) {
76
                $now = \time();
77
                $times[$now] ??= 0;
78
                $times[$now]++;
79
80
                if ($now >= ($start + $duration)) {
81
                    $response->cancel();
82
                }
83
            }
84
        } catch (TimeoutException | TransportException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
85
        }
86
87
        $average = (int) \round(\array_sum($times) / \count($times));
88
        $output->success(\sprintf('Average messages /sec: %d', $average));
89
90
        return 0;
91
    }
92
93
    protected function configure(): void
94
    {
95
        $this->setDescription('(Testing purposes) Simulates n subscribers on a Mercure Hub.');
96
        $this->addArgument('url', InputArgument::REQUIRED, 'Mercure Hub url.');
97
        $this->addOption('jwt-key', null, InputOption::VALUE_REQUIRED, 'Subscriber JWT KEY.');
98
        $this->addOption('topics', null, InputOption::VALUE_REQUIRED, 'Topics to subscribe, comma-separated.');
99
        $this->addOption('duration', null, InputOption::VALUE_OPTIONAL, 'Duration of the test, in seconds.', 10);
100
        $this->addOption('subscribers', null, InputOption::VALUE_OPTIONAL, 'Number of subscribers', 100);
101
    }
102
}
103