repman-io/repman

View on GitHub
src/Service/Telemetry.php

Summary

Maintainability
A
45 mins
Test Coverage
<?php

declare(strict_types=1);

namespace Buddy\Repman\Service;

use Buddy\Repman\Kernel;
use Buddy\Repman\Query\Admin\TelemetryQuery;
use Buddy\Repman\Service\Proxy as PackageProxy;
use Buddy\Repman\Service\Proxy\ProxyRegister;
use Buddy\Repman\Service\Telemetry\Endpoint;
use Buddy\Repman\Service\Telemetry\Entry;
use Buddy\Repman\Service\Telemetry\Entry\Downloads;
use Buddy\Repman\Service\Telemetry\Entry\Instance;
use Buddy\Repman\Service\Telemetry\Entry\Organization;
use Buddy\Repman\Service\Telemetry\Entry\Proxy;
use Buddy\Repman\Service\Telemetry\TechnicalEmail;
use Ramsey\Uuid\Uuid;
use Symfony\Component\Messenger\Transport\Receiver\MessageCountAwareInterface;

final class Telemetry
{
    private string $instanceIdFile;
    private TelemetryQuery $query;
    private Endpoint $endpoint;
    private Config $config;
    private MessageCountAwareInterface $failedTransport;
    private ProxyRegister $proxies;

    public function __construct(string $instanceIdFile, TelemetryQuery $query, Endpoint $endpoint, Config $config, MessageCountAwareInterface $failedTransport, ProxyRegister $proxies)
    {
        $this->instanceIdFile = $instanceIdFile;
        $this->query = $query;
        $this->endpoint = $endpoint;
        $this->config = $config;
        $this->failedTransport = $failedTransport;
        $this->proxies = $proxies;
    }

    public function docsUrl(): string
    {
        return 'https://repman.io/docs/standalone#telemetry';
    }

    public function generateInstanceId(): void
    {
        if (!$this->isInstanceIdPresent()) {
            \file_put_contents($this->instanceIdFile, Uuid::uuid4());
        }
    }

    public function isInstanceIdPresent(): bool
    {
        return \file_exists($this->instanceIdFile);
    }

    public function instanceId(): string
    {
        return (string) \file_get_contents($this->instanceIdFile);
    }

    public function collectAndSend(\DateTimeImmutable $date): void
    {
        $this->endpoint->send(
            new Entry(
                $date,
                new Instance(
                    $this->instanceId(),
                    Kernel::REPMAN_VERSION,
                    sprintf('%s %s', php_uname('s'), php_uname('r')),
                    PHP_MAJOR_VERSION.'.'.PHP_MINOR_VERSION.'.'.PHP_RELEASE_VERSION,
                    $this->query->usersCount(),
                    $this->failedTransport->getMessageCount(),
                    $this->getConfig(),
                ),
                $this->getOrganizations($date),
                new Downloads(
                    $this->query->proxyDownloads($date),
                    $this->query->privateDownloads($date)
                ),
                new Proxy((int) $this->proxies->all()->map(fn (PackageProxy $p) => $p->syncedPackages()->length())->sum())
            )
        );
    }

    public function addTechnicalEmail(string $technicalEmail): void
    {
        if (!$this->isInstanceIdPresent()) {
            $this->generateInstanceId();
        }

        $this->endpoint->addTechnicalEmail(new TechnicalEmail($technicalEmail, $this->instanceId()));
    }

    public function removeTechnicalEmail(string $technicalEmail): void
    {
        if (!$this->isInstanceIdPresent()) {
            return;
        }

        $this->endpoint->removeTechnicalEmail(new TechnicalEmail($technicalEmail, $this->instanceId()));
    }

    /**
     * @return Organization[]
     */
    private function getOrganizations(\DateTimeImmutable $date): array
    {
        $count = $this->query->organizationsCount();
        $limit = 100;

        $organizations = [];
        for ($offset = 0; $offset < $count; $offset += $limit) {
            foreach ($this->query->organizations($limit, $offset) as $organization) {
                $this->getPackages($organization, $date);

                $organizations[] = $organization;
            }
        }

        return $organizations;
    }

    private function getPackages(Organization $organization, \DateTimeImmutable $date): void
    {
        $count = $this->query->packagesCount($organization->id());
        $limit = 100;

        for ($offset = 0; $offset < $count; $offset += $limit) {
            $organization->addPackages(
                $this->query->packages($organization->id(), $date, $limit, $offset)
            );
        }
    }

    /**
     * @return array<string,string>
     */
    private function getConfig(): array
    {
        return array_filter(
            $this->config->getAll(),
            fn ($k) => $k !== Config::TECHNICAL_EMAIL, ARRAY_FILTER_USE_KEY
        );
    }
}