PluginProbe ʕ •ᴥ•ʔ
NitroPack – Performance, Page Speed & Cache Plugin for Core Web Vitals, CDN & Image Optimization / 1.5.7
NitroPack – Performance, Page Speed & Cache Plugin for Core Web Vitals, CDN & Image Optimization v1.5.7
1.19.8 1.19.7 1.19.6 1.19.5 trunk 1.10.0 1.10.1 1.10.2 1.10.3 1.10.4 1.11.0 1.12.0 1.13.0 1.14.0 1.15.0 1.15.1 1.15.2 1.15.3 1.16.0 1.16.1 1.16.2 1.16.3 1.16.4 1.16.5 1.16.6 1.16.7 1.16.8 1.17.0 1.17.6 1.17.7 1.17.8 1.17.9 1.18.0 1.18.1 1.18.2 1.18.3 1.18.4 1.18.5 1.18.6 1.18.7 1.18.8 1.18.9 1.19.0 1.19.1 1.19.2 1.19.3 1.19.4 1.3.19 1.3.20 1.4.0 1.4.1 1.5.0 1.5.1 1.5.10 1.5.11 1.5.12 1.5.13 1.5.14 1.5.15 1.5.16 1.5.17 1.5.18 1.5.19 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.5.9 1.6.0 1.6.1 1.7.0 1.7.1 1.8.0 1.8.1 1.8.3 1.9.0 1.9.1 1.9.2
nitropack / nitropack-sdk / NitroPack / SDK / Backlog.php
nitropack / nitropack-sdk / NitroPack / SDK Last commit date
Api 5 years ago Integrations 6 years ago StorageDriver 4 years ago Url 6 years ago data 6 years ago Api.php 5 years ago Backlog.php 5 years ago Crypto.php 6 years ago Device.php 6 years ago DeviceType.php 6 years ago EmptyConfigException.php 6 years ago FileHandle.php 5 years ago Filesystem.php 4 years ago HealthStatus.php 5 years ago IntegrationUrl.php 6 years ago NitroPack.php 4 years ago NoConfigException.php 5 years ago Pagecache.php 4 years ago PurgeType.php 6 years ago ServiceDownException.php 5 years ago StorageException.php 6 years ago VariationCookieException.php 5 years ago WebhookException.php 5 years ago Website.php 6 years ago
Backlog.php
233 lines
1 <?php
2
3 namespace NitroPack\SDK;
4 use NitroPack\SDK\Api\ResponseStatus;
5
6 class Backlog {
7 const TTL = 86400; // 1 day in seconds
8
9 private $dataDir;
10 private $nitropack;
11 private $communicators;
12 private $queue;
13 private $queuePath;
14 private $isAcquired;
15 private $fileHandle;
16 private $header;
17 private $backlogFile = array('data', 'backlog.queue');
18
19 public function __construct($dataDir, $nitropack) {
20 $this->dataDir = $dataDir;
21 $this->nitropack = $nitropack;
22 $this->communicators = array();
23 $this->queue = array();
24 $this->queuePath = $this->getQueuePath();
25 $this->isAcquired = false;
26 $this->fileHandle = NULL;
27 $this->header = new \stdClass();
28 $this->header->offset = 0;
29 $this->header->firstProcessingTimestamp = 0;
30 $this->header->lastProcessingTimestamp = 0;
31 }
32
33 public function __destruct() {
34 $this->closeHandle();
35 }
36
37 public function append($entry) {
38 if (defined("NITROPACK_DISABLE_BACKLOG")) return;
39 $fh = $this->getHandle();
40 Filesystem::flock($fh, LOCK_EX);
41 Filesystem::fseek($fh, 0, SEEK_END);
42 $this->writeEntry($fh, $this->encodeEntry($entry));
43 Filesystem::flock($fh, LOCK_UN);
44 }
45
46 public function replay($timeLimit = 10) {
47 if (defined("NITROPACK_DISABLE_BACKLOG")) return;
48 $fh = $this->getHandle();
49 Filesystem::flock($fh, LOCK_EX);
50 $lastProcessingTimestamp = $this->header->lastProcessingTimestamp;
51 if (time() - $lastProcessingTimestamp <= $timeLimit) {
52 return;
53 }
54 $this->acquireBacklog($fh);
55 Filesystem::flock($fh, LOCK_UN);
56
57 $initialProcesssTime = $this->header->firstProcessingTimestamp;
58 if (time() - $initialProcesssTime > self::TTL) {
59 // In case there have been previous attempts at clearing the backlog and these attempts started more than the specified TTL seconds ago
60 // Perform a full purge and clear the backlog
61 }
62
63 if ($this->header->offset > 0) {
64 Filesystem::fseek($fh, $this->header->offset, SEEK_SET);
65 }
66 $start = microtime(true);
67 while (!$this->isEndOfQueue($fh) && NULL != ($entry = $this->getentry($fh)) && microtime(true) - $start < $timeLimit) {
68 $elapsedTime = microtime(true) - $start;
69 try {
70 $this->replayEntry($entry, $timeLimit - $elapsedTime);
71 } catch (\Exception $e) {
72 break;
73 }
74 }
75
76 if ($this->isEndOfQueue($fh)) {
77 $this->closeHandle();
78 Filesystem::deleteFile($this->queuePath);
79 }
80 }
81
82 private function isEndOfQueue($fh) {
83 return Filesystem::feof($fh);
84 }
85
86 public function dumpEntries() {
87 $fh = $this->getHandle();
88 while (!$this->isEndOfQueue($fh) && NULL != ($entry = $this->getentry($fh))) {
89 try {
90 var_dump($entry);
91 } catch (\Exception $e) {
92 break;
93 }
94 }
95 }
96
97 public function dumpHeader() {
98 $this->getHandle();
99 var_dump($this->header);
100 }
101
102 public function resetOffset() {
103 $fh = $this->getHandle();
104 $this->header->offset = 0;
105 $this->writeHeader($fh);
106 }
107
108 public function exists() {
109 if (defined("NITROPACK_DISABLE_BACKLOG")) return false;
110 return Filesystem::fileExists($this->queuePath);
111 }
112
113 private function replayEntry($entry, $timeLimit) {
114 if (array_key_exists("siteSecret", $entry)) {
115 $requestMaker = $this->nitropack->getApi()->secure_request_maker;
116 } else {
117 $requestMaker = $this->nitropack->getApi()->request_maker;
118 }
119 $httpResponse = $requestMaker->makeRequest($entry["path"], $entry["headers"], $entry["cookies"], $entry["type"], $entry["bodyData"], false, $entry["verifySSL"]);
120 $status = ResponseStatus::getStatus($httpResponse->getStatusCode());
121 $headers = $httpResponse->getHeaders();
122
123 $start = microtime(true);
124 while ($status == ResponseStatus::OK && !empty($headers["x-nitro-repeat"]) && microtime(true) - $start < $timeLimit) {
125 $httpResponse->replay(); // In reality $httpResponse is an instance of HttpClient which has the replay method
126 $status = ResponseStatus::getStatus($httpResponse->getStatusCode());
127 $headers = $httpResponse->getHeaders();
128 if ($status != ResponseStatus::OK) {
129 throw \RuntimeException("Unable to replay backlogged entry");
130 }
131 }
132
133 if ($status == ResponseStatus::OK && empty($headers["x-nitro-repeat"])) {
134 $fh = $this->getHandle();
135 $this->header->offset = Filesystem::ftell($fh);
136 $this->writeHeader($fh);
137 }
138 }
139
140 private function getQueuePath() {
141 $backlogFile = $this->backlogFile;
142 array_unshift($backlogFile, $this->dataDir);
143 return Filesystem::getOsPath($backlogFile);
144 }
145
146 private function getEntry($fh = NULL) {
147 $closeFile = empty($fh);
148 $fh = !empty($fh) ? $fh : $this->getHandle();
149 $entry = @Filesystem::fgets($fh);
150 if ($closeFile) {
151 Filesystem::fclose($fh);
152 }
153 return $this->decodeEntry($entry);
154 }
155
156 private function writeEntry($fh, $entry) {
157 Filesystem::fwrite($fh, $entry . "\n");
158 Filesystem::fflush($fh);
159 }
160
161 private function encodeEntry($entry) {
162 return base64_encode(json_encode($entry));
163 }
164
165 private function decodeEntry($entry) {
166 return json_decode(base64_decode($entry), true);
167 }
168
169 private function acquireBacklog($fh) {
170 $this->header->lastProcessingTimestamp = time();
171 if (!$this->header->firstProcessingTimestamp) {
172 $this->header->firstProcessingTimestamp = $this->header->lastProcessingTimestamp;
173 }
174 $this->writeHeader($fh);
175 $this->isAcquired = true;
176 }
177
178 private function releaseBacklog($fh) {
179 $this->header->lastProcessingTimestamp = 0;
180 $this->writeHeader($fh);
181 $this->isAcquired = false;
182 }
183
184 private function readHeader($fh) {
185 $offsetBackup = Filesystem::ftell($fh);
186 Filesystem::fseek($fh, 0, SEEK_SET);
187 $header = Filesystem::fread($fh, 12);
188 $parts = unpack("Loffset/LfirstProcessingTimestamp/LlastProcessingTimestamp", $header);
189 $this->header->offset = $parts["offset"];
190 $this->header->firstProcessingTimestamp = $parts["firstProcessingTimestamp"];
191 $this->header->lastProcessingTimestamp = $parts["lastProcessingTimestamp"];
192 Filesystem::fseek($fh, $offsetBackup, SEEK_SET);
193 }
194
195 private function writeHeader($fh) {
196 $offsetBackup = Filesystem::ftell($fh);
197 Filesystem::fseek($fh, 0, SEEK_SET);
198 Filesystem::fwrite($fh, pack("L*", $this->header->offset, $this->header->firstProcessingTimestamp, $this->header->lastProcessingTimestamp), 12);
199 Filesystem::fflush($fh);
200 Filesystem::fseek($fh, $offsetBackup, SEEK_SET);
201 }
202
203 private function getHandle() {
204 if ($this->fileHandle) return $this->fileHandle;
205
206 $fh = Filesystem::fopen($this->queuePath, "c+");
207 Filesystem::flock($fh, LOCK_EX);
208 Filesystem::fseek($fh, 0, SEEK_END);
209 $pos = Filesystem::ftell($fh);
210 if ($pos > 11) { // The first 12 bytes are reserved for the header. If the last pos is further than the 12th byte then the log is considered initialized
211 $this->readHeader($fh);
212 } else {
213 $this->writeHeader($fh);
214 }
215 Filesystem::fseek($fh, 12, SEEK_SET);
216 Filesystem::flock($fh, LOCK_UN);
217
218 $this->fileHandle = $fh;
219
220 return $this->fileHandle;
221 }
222
223 private function closeHandle() {
224 if ($this->fileHandle) {
225 if ($this->isAcquired) {
226 $this->releaseBacklog($this->fileHandle);
227 }
228 Filesystem::fclose($this->fileHandle);
229 $this->fileHandle = NULL;
230 }
231 }
232 }
233