Skip to content

Commit 0d4c229

Browse files
Merge pull request #140 from neo4j-php/analytics
added mixpanel analytics
2 parents 5639c82 + 1d27d7c commit 0d4c229

File tree

6 files changed

+86
-12
lines changed

6 files changed

+86
-12
lines changed

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,12 @@ environments for security reasons._
255255

256256
Server state is not reported by server but it is evaluated by received response. You can access current state through property `$protocol->serverState`. This property is updated with every call `getResponse(s)`.
257257

258+
## :bar_chart: Analytics
259+
260+
Bolt does collect anonymous analytics data. These data are stored offline (as files in temp directory) and submitted once a day. You can opt out with environment variable `BOLT_ANALYTICS_OPTOUT`.
261+
262+
Analytics data are public and available at [Mixpanel](https://eu.mixpanel.com/p/7ttVKqvjdqJtGCjLCFgdeC).
263+
258264
## :pushpin: More solutions
259265

260266
If you need simple class to cover basic functionality you can

composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
"require": {
1111
"php": "^8.1",
1212
"ext-mbstring": "*",
13+
"ext-curl": "*",
1314
"psr/simple-cache": "^3.0"
1415
},
1516
"require-dev": {

src/Bolt.php

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,56 @@ final class Bolt
2626

2727
public function __construct(private IConnection $connection)
2828
{
29+
if (!file_exists(getcwd() . DIRECTORY_SEPARATOR . 'temp' . DIRECTORY_SEPARATOR)) {
30+
mkdir(getcwd() . DIRECTORY_SEPARATOR . 'temp');
31+
}
32+
if (!getenv('BOLT_ANALYTICS_OPTOUT')) {
33+
$this->track();
34+
}
2935
$this->setProtocolVersions(5.4, 5, 4.4);
3036
}
3137

38+
private function track(): void
39+
{
40+
foreach (glob(getcwd() . DIRECTORY_SEPARATOR . 'temp' . DIRECTORY_SEPARATOR . 'queries.*.cnt') as $file) {
41+
$time = intval(explode('.', basename($file))[1]);
42+
if ($time < strtotime('today')) {
43+
$count = file_get_contents($file);
44+
unlink($file);
45+
46+
$curl = curl_init();
47+
curl_setopt_array($curl, [
48+
CURLOPT_URL => 'https://api-eu.mixpanel.com/import?strict=0&project_id=3355308',
49+
CURLOPT_RETURNTRANSFER => true,
50+
CURLOPT_ENCODING => '',
51+
CURLOPT_MAXREDIRS => 10,
52+
CURLOPT_TIMEOUT => $this->connection->getTimeout(),
53+
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
54+
CURLOPT_CUSTOMREQUEST => 'POST',
55+
CURLOPT_SSL_VERIFYPEER => false,
56+
CURLOPT_POSTFIELDS => json_encode([
57+
[
58+
'properties' => [
59+
'$insert_id' => $file,
60+
'distinct_id' => sha1(implode('', [php_uname(), disk_total_space('.'), filectime('/'), phpversion()])),
61+
'amount' => $count,
62+
'time' => $time
63+
],
64+
'event' => 'queries'
65+
]
66+
]),
67+
CURLOPT_HTTPHEADER => [
68+
'Content-Type: application/json',
69+
'accept: application/json',
70+
'authorization: Basic MDJhYjRiOWE2YTM4MThmNWFlZDEzYjNiMmE5M2MxNzQ6',
71+
],
72+
]);
73+
curl_exec($curl);
74+
curl_close($curl);
75+
}
76+
}
77+
}
78+
3279
/**
3380
* Connect via Connection, execute handshake on it, create and return protocol version class
3481
* @throws BoltException

src/helpers/FileCache.php

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,22 @@
1313
*/
1414
class FileCache implements CacheInterface
1515
{
16+
private string $tempDir;
17+
1618
public function __construct()
1719
{
18-
if (!file_exists(__DIR__ . DIRECTORY_SEPARATOR . 'temp' . DIRECTORY_SEPARATOR))
19-
mkdir(__DIR__ . DIRECTORY_SEPARATOR . 'temp');
20+
$this->tempDir = getcwd() . DIRECTORY_SEPARATOR . 'temp' . DIRECTORY_SEPARATOR;
21+
22+
if (!file_exists($this->tempDir)) {
23+
mkdir(rtrim($this->tempDir, DIRECTORY_SEPARATOR));
24+
}
2025

2126
// clean old
22-
foreach (scandir(__DIR__ . DIRECTORY_SEPARATOR . 'temp') as $file) {
27+
foreach (scandir($this->tempDir . 'temp') as $file) {
2328
if ($file == '.' || $file == '..')
2429
continue;
25-
if (filemtime(__DIR__ . DIRECTORY_SEPARATOR . 'temp' . DIRECTORY_SEPARATOR . $file) < strtotime('-1 hour'))
26-
unlink(__DIR__ . DIRECTORY_SEPARATOR . 'temp' . DIRECTORY_SEPARATOR . $file);
30+
if (filemtime($this->tempDir . $file) < strtotime('-1 hour'))
31+
unlink($this->tempDir . $file);
2732
}
2833
}
2934

@@ -37,7 +42,7 @@ public function __construct()
3742
*/
3843
public function get(string $key, mixed $default = null): mixed
3944
{
40-
return $this->has($key) ? file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . 'temp' . DIRECTORY_SEPARATOR . $key) : $default;
45+
return $this->has($key) ? file_get_contents($this->tempDir . $key) : $default;
4146
}
4247

4348
/**
@@ -53,7 +58,7 @@ public function get(string $key, mixed $default = null): mixed
5358
*/
5459
public function set(string $key, mixed $value, \DateInterval|int|null $ttl = null): bool
5560
{
56-
return is_int(file_put_contents(__DIR__ . DIRECTORY_SEPARATOR . 'temp' . DIRECTORY_SEPARATOR . $key, $value));
61+
return is_int(file_put_contents($this->tempDir . $key, $value));
5762
}
5863

5964
/**
@@ -65,18 +70,18 @@ public function set(string $key, mixed $value, \DateInterval|int|null $ttl = nul
6570
*/
6671
public function delete(string $key): bool
6772
{
68-
return $this->has($key) && unlink(__DIR__ . DIRECTORY_SEPARATOR . 'temp' . DIRECTORY_SEPARATOR . $key);
73+
return $this->has($key) && unlink($this->tempDir . $key);
6974
}
7075

7176
/**
7277
* @inheritDoc
7378
*/
7479
public function clear(): bool
7580
{
76-
foreach (scandir(__DIR__ . DIRECTORY_SEPARATOR . 'temp') as $file) {
81+
foreach (scandir(rtrim($this->tempDir, DIRECTORY_SEPARATOR)) as $file) {
7782
if ($file == '.' || $file == '..')
7883
continue;
79-
unlink(__DIR__ . DIRECTORY_SEPARATOR . 'temp' . DIRECTORY_SEPARATOR . $file);
84+
unlink($this->tempDir . $file);
8085
}
8186
return true;
8287
}
@@ -143,6 +148,6 @@ public function deleteMultiple(iterable $keys): bool
143148
*/
144149
public function has(string $key): bool
145150
{
146-
return file_exists(__DIR__ . DIRECTORY_SEPARATOR . 'temp' . DIRECTORY_SEPARATOR . $key);
151+
return file_exists($this->tempDir . $key);
147152
}
148153
}

src/protocol/AProtocol.php

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,19 @@ public function __construct(
6363
*/
6464
protected function write(iterable $generator): void
6565
{
66-
foreach ($generator as $buffer)
66+
if (!getenv('BOLT_ANALYTICS_OPTOUT')) {
67+
$this->track();
68+
}
69+
foreach ($generator as $buffer) {
6770
$this->connection->write($buffer);
71+
}
72+
}
73+
74+
private function track(): void
75+
{
76+
$file = getcwd() . DIRECTORY_SEPARATOR . 'temp' . DIRECTORY_SEPARATOR . 'queries.' . strtotime('today') . '.cnt';
77+
$count = file_exists($file) ? intval(file_get_contents($file)) : 0;
78+
file_put_contents($file, $count + 1);
6879
}
6980

7081
/**

tests/protocol/ATest.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,10 @@ public function readCallback(int $length = 2048): string
100100
*/
101101
protected function setUp(): void
102102
{
103+
if (!file_exists(getcwd() . DIRECTORY_SEPARATOR . 'temp' . DIRECTORY_SEPARATOR)) {
104+
mkdir(getcwd() . DIRECTORY_SEPARATOR . 'temp');
105+
}
106+
103107
self::$readBuffer = '';
104108
self::$readArray = [];
105109
self::$writeIndex = 0;

0 commit comments

Comments
 (0)