Issues (106)

src/Infrastructure/GoogleApiQuota.php (1 issue)

Labels
Severity
1
<?php
2
/*
3
 * This file is part of dispositif/wikibot application (@github)
4
 * 2019-2023 © Philippe M./Irønie  <[email protected]>
5
 * For the full copyright and MIT license information, view the license file.
6
 */
7
8
declare(strict_types=1);
9
10
namespace App\Infrastructure;
11
12
use App\Domain\Exceptions\ConfigException;
13
use App\Domain\InfrastructurePorts\GoogleApiQuotaInterface;
14
use DateTime;
15
use DateTimeZone;
16
use Exception;
17
use Throwable;
18
19
/**
20
 * Count and increment, data saved in json file.
21
 * Set count to 0 everyday at 00:00 (America/Los_Angeles).
22
 * No need of SQL/singleton with the single file.
23
 * /!\ Will fail with too many concurrent requests.
24
 * Class GoogleRequestQuota
25
 *
26
 * @package App\Infrastructure
27
 */
28
class GoogleApiQuota implements GoogleApiQuotaInterface
29
{
30
    /** {"date":"2020-03-23T00:19:56-07:00","count":43}  */
31
    final public const JSON_FILENAME   = __DIR__.'/resources/google_quota.json';
32
    final public const REBOOT_TIMEZONE = 'America/Los_Angeles';
33
    final public const REBOOT_HOUR     = 0;
34
    final public const DAILY_QUOTA     = 1000;
35
36
    private DateTime $lastDate;
37
    private int $count = 0;
38
    /**
39
     * @var DateTime Today reboot date/time of the quota
40
     */
41
    private readonly DateTime $todayBoot;
42
43
    /**
44
     * GoogleRequestQuota constructor.
45
     *
46
     * @throws Exception
47
     */
48
    public function __construct()
49
    {
50
        $data = $this->getFileData();
51
        $this->lastDate = new DateTime($data['date'], new DateTimeZone(static::REBOOT_TIMEZONE));
52
        $this->count = (int)$data['count'];
53 1
54
        // Today reboot date/time of the quota
55 1
        $todayBoot = new DateTime();
56 1
        $todayBoot->setTimezone(new DateTimeZone('America/Los_Angeles'))->setTime(static::REBOOT_HOUR, 0);
57 1
        $this->todayBoot = $todayBoot;
0 ignored issues
show
The property todayBoot is declared read-only in App\Infrastructure\GoogleApiQuota.
Loading history...
58
59
        $this->checkNewReboot();
60 1
    }
61 1
62 1
    /**
63
     * @throws ConfigException
64 1
     */
65 1
    private function getFileData(): array
66
    {
67
        if (!file_exists(static::JSON_FILENAME)) {
68
            return ['date' => '2020-01-01T00:00:20-07:00', 'count' => 0];
69
        }
70
71 1
        try {
72
            $json = file_get_contents(static::JSON_FILENAME);
73 1
            $array = (array)json_decode($json, true, 512, JSON_THROW_ON_ERROR);
74 1
        } catch (Throwable) {
75
            throw new ConfigException('Error on Google Quota file : reading or JSON malformed.');
76
        }
77
78
        return $array;
79
    }
80
81
    private function checkNewReboot(): void
82
    {
83
        $now = new DateTime();
84
        $now->setTimezone(new DateTimeZone(static::REBOOT_TIMEZONE));
85
86
        if ($now->diff($this->lastDate, true)->format('%h') > 24) {
87 1
            $this->setZero();
88
89 1
            return;
90 1
        }
91
        if ($this->lastDate < $this->todayBoot && $now > $this->todayBoot) {
92 1
            $this->setZero();
93
        }
94
    }
95
96
    private function setZero(): void
97 1
    {
98 1
        $now = new DateTime();
99
        $now->setTimezone(new DateTimeZone(static::REBOOT_TIMEZONE));
100 1
        $this->lastDate = $now;
101
        $this->count = 0;
102 1
        $this->saveDateInFile();
103
    }
104 1
105 1
    /**
106 1
     * @throws ConfigException
107 1
     */
108 1
    private function saveDateInFile(): void
109 1
    {
110
        $data = [
111
            'type' => 'Google API Quota',
112
            'date' => $this->lastDate->format('c'),
113
            'count' => $this->count,
114 1
        ];
115
        $result = file_put_contents(static::JSON_FILENAME, json_encode($data, JSON_THROW_ON_ERROR));
116
        if ($result === false) {
117 1
            throw new ConfigException("Can't write on Google Quota file.");
118 1
        }
119 1
    }
120
121 1
    public function getCount(): int
122 1
    {
123
        $this->checkNewReboot();
124
125 1
        return $this->count;
126
    }
127
128
    public function isQuotaReached(): bool
129
    {
130
        $this->checkNewReboot();
131
        return $this->count >= static::DAILY_QUOTA;
132
    }
133
134
    /**
135
     *
136
     */
137
    public function increment(): void
138
    {
139
        $this->checkNewReboot();
140
        $this->count += 1;
141
        $this->saveDateInFile();
142
    }
143
}
144