Skip to content

Commit a64cf42

Browse files
Merge pull request #159 from neo4j-php/file_cache_improvement
added locking mechanism into FileCache. use FileCache also for analytics data.
2 parents 9cc7dfa + dbf87d0 commit a64cf42

File tree

9 files changed

+462
-153
lines changed

9 files changed

+462
-153
lines changed

phpunit.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
</testsuite>
1212
<testsuite name="NoDatabase">
1313
<directory>./tests/protocol</directory>
14+
<file>./tests/helpers/FileCacheTest.php</file>
1415
</testsuite>
1516
</testsuites>
1617
<php>

src/Bolt.php

Lines changed: 86 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use Bolt\protocol\AProtocol;
88
use Bolt\enum\{Signature, ServerState};
99
use Bolt\connection\IConnection;
10+
use Bolt\helpers\CacheProvider;
1011

1112
/**
1213
* Main class Bolt
@@ -38,53 +39,72 @@ public function __construct(private IConnection $connection)
3839

3940
private function track(): void
4041
{
41-
foreach (glob(sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'php-bolt-analytics' . DIRECTORY_SEPARATOR . 'analytics.*.json') as $file) {
42-
$time = intval(explode('.', basename($file))[1]);
42+
$data = (array)CacheProvider::get()->get('analytics', []);
43+
if (empty($data)) {
44+
return;
45+
}
46+
47+
$distinctId = sha1(implode('', [php_uname(), disk_total_space('.'), filectime('/'), phpversion()]));
48+
49+
$toSend = [];
50+
foreach ($data as $time => $counts) {
4351
if ($time < strtotime('today')) {
44-
$data = (array)json_decode((string)file_get_contents($file), true);
45-
$distinctId = sha1(implode('', [php_uname(), disk_total_space('.'), filectime('/'), phpversion()]));
46-
47-
$curl = curl_init();
48-
curl_setopt_array($curl, [
49-
CURLOPT_URL => 'https://api-eu.mixpanel.com/import?strict=0&project_id=3355308',
50-
CURLOPT_RETURNTRANSFER => true,
51-
CURLOPT_ENCODING => '',
52-
CURLOPT_MAXREDIRS => 10,
53-
CURLOPT_TIMEOUT => $this->connection->getTimeout(),
54-
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
55-
CURLOPT_CUSTOMREQUEST => 'POST',
56-
CURLOPT_SSL_VERIFYPEER => false,
57-
CURLOPT_POSTFIELDS => json_encode([
58-
[
59-
'properties' => [
60-
'$insert_id' => (string)$time,
61-
'distinct_id' => $distinctId,
62-
'amount' => $data['queries'] ?? 0,
63-
'time' => $time
64-
],
65-
'event' => 'queries'
66-
],
67-
[
68-
'properties' => [
69-
'$insert_id' => (string)$time,
70-
'distinct_id' => $distinctId,
71-
'amount' => $data['sessions'] ?? 0,
72-
'time' => $time
73-
],
74-
'event' => 'sessions'
75-
]
76-
]),
77-
CURLOPT_HTTPHEADER => [
78-
'Content-Type: application/json',
79-
'accept: application/json',
80-
'authorization: Basic MDJhYjRiOWE2YTM4MThmNWFlZDEzYjNiMmE5M2MxNzQ6',
52+
$toSend[] = [
53+
'properties' => [
54+
'$insert_id' => (string) $time,
55+
'distinct_id' => $distinctId,
56+
'amount' => $counts['queries'] ?? 0,
57+
'time' => $time
8158
],
82-
]);
59+
'event' => 'queries'
60+
];
61+
$toSend[] = [
62+
'properties' => [
63+
'$insert_id' => (string) $time,
64+
'distinct_id' => $distinctId,
65+
'amount' => $counts['sessions'] ?? 0,
66+
'time' => $time
67+
],
68+
'event' => 'sessions'
69+
];
70+
}
71+
}
8372

84-
if (curl_exec($curl) !== false) {
85-
@unlink($file);
73+
//curl
74+
$curl = curl_init();
75+
curl_setopt_array($curl, [
76+
CURLOPT_URL => 'https://api-eu.mixpanel.com/import?strict=0&project_id=3355308',
77+
CURLOPT_RETURNTRANSFER => true,
78+
CURLOPT_ENCODING => '',
79+
CURLOPT_MAXREDIRS => 10,
80+
CURLOPT_TIMEOUT => $this->connection->getTimeout(),
81+
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
82+
CURLOPT_CUSTOMREQUEST => 'POST',
83+
CURLOPT_SSL_VERIFYPEER => false,
84+
CURLOPT_POSTFIELDS => json_encode($toSend),
85+
CURLOPT_HTTPHEADER => [
86+
'Content-Type: application/json',
87+
'accept: application/json',
88+
'authorization: Basic MDJhYjRiOWE2YTM4MThmNWFlZDEzYjNiMmE5M2MxNzQ6',
89+
],
90+
]);
91+
92+
if (curl_exec($curl) !== false) {
93+
curl_close($curl);
94+
95+
// clean sent analytics data
96+
if (method_exists(CacheProvider::get(), 'lock')) {
97+
CacheProvider::get()->lock('analytics');
98+
}
99+
$data = (array)CacheProvider::get()->get('analytics');
100+
foreach ($data as $time => $counts) {
101+
if ($time < strtotime('today')) {
102+
unset($data[$time]);
86103
}
87-
curl_close($curl);
104+
}
105+
CacheProvider::get()->set('analytics', $data);
106+
if (method_exists(CacheProvider::get(), 'unlock')) {
107+
CacheProvider::get()->unlock('analytics');
88108
}
89109
}
90110
}
@@ -102,10 +122,7 @@ public function build(): AProtocol
102122
throw new ConnectException('Connection failed');
103123
}
104124

105-
if ($this->connection instanceof \Bolt\connection\PStreamSocket) {
106-
$protocol = $this->persistentBuild();
107-
}
108-
125+
$protocol = $this->persistentBuild();
109126
if (empty($protocol)) {
110127
$protocol = $this->normalBuild();
111128
}
@@ -115,7 +132,7 @@ public function build(): AProtocol
115132
}
116133

117134
if ($this->connection instanceof \Bolt\connection\PStreamSocket) {
118-
$this->connection->getCache()->set($this->connection->getIdentifier(), $protocol->getVersion());
135+
CacheProvider::get()->set($this->connection->getIdentifier(), $protocol->getVersion(), strtotime('+15 minutes'));
119136
}
120137

121138
return $protocol;
@@ -137,27 +154,30 @@ private function normalBuild(): AProtocol
137154

138155
private function persistentBuild(): ?AProtocol
139156
{
140-
$version = $this->connection->getCache()->get($this->connection->getIdentifier());
141-
if (empty($version)) {
142-
return null;
143-
}
157+
if ($this->connection instanceof \Bolt\connection\PStreamSocket) {
158+
$version = CacheProvider::get()->get($this->connection->getIdentifier());
159+
if (empty($version)) {
160+
return null;
161+
}
144162

145-
$protocolClass = "\\Bolt\\protocol\\V" . str_replace('.', '_', $version);
146-
if (!class_exists($protocolClass)) {
147-
throw new ConnectException('Requested Protocol version (' . $version . ') not yet implemented');
148-
}
163+
$protocolClass = "\\Bolt\\protocol\\V" . str_replace('.', '_', $version);
164+
if (!class_exists($protocolClass)) {
165+
throw new ConnectException('Requested Protocol version (' . $version . ') not yet implemented');
166+
}
149167

150-
/** @var AProtocol $protocol */
151-
$protocol = new $protocolClass($this->packStreamVersion, $this->connection);
152-
$protocol->serverState = ServerState::INTERRUPTED;
168+
/** @var AProtocol $protocol */
169+
$protocol = new $protocolClass($this->packStreamVersion, $this->connection);
170+
$protocol->serverState = ServerState::INTERRUPTED;
153171

154-
if ($protocol->reset()->getResponse()->signature != Signature::SUCCESS) {
155-
$this->connection->disconnect();
156-
$this->connection->connect();
157-
return null;
158-
}
172+
if ($protocol->reset()->getResponse()->signature != Signature::SUCCESS) {
173+
$this->connection->disconnect();
174+
$this->connection->connect();
175+
return null;
176+
}
159177

160-
return $protocol;
178+
return $protocol;
179+
}
180+
return null;
161181
}
162182

163183
public function setProtocolVersions(int|float|string ...$v): Bolt
@@ -224,7 +244,7 @@ private function packProtocolVersions(): string
224244
if (is_int($v))
225245
$versions[] = pack('N', $v);
226246
else {
227-
$splitted = explode('.', (string)$v);
247+
$splitted = explode('.', (string) $v);
228248
$splitted = array_reverse($splitted);
229249
while (count($splitted) < 4)
230250
array_unshift($splitted, 0);

src/autoload.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
if (reset($parts) == 'tests')
1313
array_unshift($parts,'..');
1414

15-
//compose standart namespaced path to file
15+
//compose standard namespaced path to file
1616
$path = __DIR__ . DS . implode(DS, $parts) . '.php';
1717
if (file_exists($path)) {
1818
require_once $path;

src/connection/PStreamSocket.php

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33

44
namespace Bolt\connection;
55

6-
use Bolt\helpers\FileCache;
76
use Psr\SimpleCache\CacheInterface;
7+
use Bolt\helpers\CacheProvider;
88

99
/**
1010
* Persistent stream socket class
@@ -22,20 +22,23 @@
2222
class PStreamSocket extends StreamSocket
2323
{
2424
private string $identifier;
25-
private CacheInterface $cache;
2625

2726
protected int $connectionFlags = STREAM_CLIENT_CONNECT | STREAM_CLIENT_PERSISTENT;
2827

28+
/**
29+
* @deprecated Cache is no longer held in this class. Use CacheProvider::set() instead.
30+
*/
2931
public function setCache(CacheInterface $cache): void
3032
{
31-
$this->cache = $cache;
33+
CacheProvider::set($cache);
3234
}
3335

36+
/**
37+
* @deprecated Cache is no longer held in this class. Use CacheProvider::get() instead.
38+
*/
3439
public function getCache(): CacheInterface
3540
{
36-
if (empty($this->cache))
37-
$this->cache = new FileCache();
38-
return $this->cache;
41+
return CacheProvider::get();
3942
}
4043

4144
public function connect(): bool
@@ -67,7 +70,7 @@ public function disconnect(): void
6770
stream_socket_shutdown($this->stream, STREAM_SHUT_RDWR);
6871
fclose($this->stream);
6972
unset($this->stream);
70-
$this->getCache()->delete($this->getIdentifier());
73+
CacheProvider::get()->delete($this->getIdentifier());
7174
}
7275
}
7376
}

src/helpers/CacheProvider.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
namespace Bolt\helpers;
4+
5+
use Psr\SimpleCache\CacheInterface;
6+
7+
/**
8+
* Class CacheProvider
9+
*
10+
* @author Michal Stefanak
11+
* @link https://github.com/neo4j-php/Bolt
12+
* @package Bolt\helpers
13+
*/
14+
class CacheProvider
15+
{
16+
private static CacheInterface $cache;
17+
18+
public static function get(): CacheInterface
19+
{
20+
if (empty(self::$cache))
21+
self::$cache = new FileCache();
22+
return self::$cache;
23+
}
24+
25+
public static function set(CacheInterface $cache): void
26+
{
27+
self::$cache = $cache;
28+
}
29+
}

0 commit comments

Comments
 (0)