Refactored cache drivers 🗃 (#1553)

* Refactored cache drivers 🗃

* Updated

* Update APCu.php

* Update APCu.php

* Update APCu.php

* Update APCu.php

* Update APCu.php

* Update Redis.php

* Update Redis.php

* Updated

* Update

* Updated

* Update config.php

* Updated

* Updated

* Updated

* Updated

* Update config.php

* Updated

* Update composer.lock

* Delete composer.lock

* Create composer.lock

* Update composer.lock

* Update common.php

* Update File.php

* Updated

* Update Sqlite.php

* Update common.php

* Update Redis.php

* Updated

* Update common.php

* Updated
This commit is contained in:
Roman Kelesidis 2024-07-22 14:55:04 +07:00 committed by GitHub
parent bfd61166be
commit 17a320b7c8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
23 changed files with 1561 additions and 1066 deletions

View file

@ -129,24 +129,15 @@ switch ($bb_cfg['datastore_type']) {
case 'apcu': case 'apcu':
$datastore = new TorrentPier\Legacy\Datastore\APCu($bb_cfg['cache']['prefix']); $datastore = new TorrentPier\Legacy\Datastore\APCu($bb_cfg['cache']['prefix']);
break; break;
case 'memcached':
case 'memcache': $datastore = new TorrentPier\Legacy\Datastore\Memcached($bb_cfg['cache']['memcached'], $bb_cfg['cache']['prefix']);
$datastore = new TorrentPier\Legacy\Datastore\Memcache($bb_cfg['cache']['memcache'], $bb_cfg['cache']['prefix']);
break; break;
case 'sqlite': case 'sqlite':
$default_cfg = [ $datastore = new TorrentPier\Legacy\Datastore\Sqlite($bb_cfg['cache']['db_dir'] . 'datastore', $bb_cfg['cache']['prefix']);
'db_file_path' => $bb_cfg['cache']['db_dir'] . 'datastore.sqlite.db',
'pconnect' => true,
'con_required' => true,
];
$datastore = new TorrentPier\Legacy\Datastore\Sqlite($default_cfg, $bb_cfg['cache']['prefix']);
break; break;
case 'redis': case 'redis':
$datastore = new TorrentPier\Legacy\Datastore\Redis($bb_cfg['cache']['redis'], $bb_cfg['cache']['prefix']); $datastore = new TorrentPier\Legacy\Datastore\Redis($bb_cfg['cache']['redis'], $bb_cfg['cache']['prefix']);
break; break;
case 'filecache': case 'filecache':
default: default:
$datastore = new TorrentPier\Legacy\Datastore\File($bb_cfg['cache']['db_dir'] . 'datastore/', $bb_cfg['cache']['prefix']); $datastore = new TorrentPier\Legacy\Datastore\File($bb_cfg['cache']['db_dir'] . 'datastore/', $bb_cfg['cache']['prefix']);

View file

@ -48,7 +48,9 @@
"google/recaptcha": "^1.3", "google/recaptcha": "^1.3",
"jacklul/monolog-telegram": "^3.1", "jacklul/monolog-telegram": "^3.1",
"josantonius/cookie": "^2.0", "josantonius/cookie": "^2.0",
"league/flysystem": "^3.28",
"longman/ip-tools": "1.2.1", "longman/ip-tools": "1.2.1",
"matthiasmullie/scrapbook": "^1.5",
"monolog/monolog": "^3.4", "monolog/monolog": "^3.4",
"samdark/sitemap": "2.4.1", "samdark/sitemap": "2.4.1",
"symfony/mailer": "^6.3", "symfony/mailer": "^6.3",

456
composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "4978862c1744c10fc0986a0ef31f0e81", "content-hash": "5bf770ec31048776ac6470189024cb19",
"packages": [ "packages": [
{ {
"name": "arokettu/bencode", "name": "arokettu/bencode",
@ -516,16 +516,16 @@
}, },
{ {
"name": "composer/ca-bundle", "name": "composer/ca-bundle",
"version": "1.5.0", "version": "1.5.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/composer/ca-bundle.git", "url": "https://github.com/composer/ca-bundle.git",
"reference": "0c5ccfcfea312b5c5a190a21ac5cef93f74baf99" "reference": "063d9aa8696582f5a41dffbbaf3c81024f0a604a"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/composer/ca-bundle/zipball/0c5ccfcfea312b5c5a190a21ac5cef93f74baf99", "url": "https://api.github.com/repos/composer/ca-bundle/zipball/063d9aa8696582f5a41dffbbaf3c81024f0a604a",
"reference": "0c5ccfcfea312b5c5a190a21ac5cef93f74baf99", "reference": "063d9aa8696582f5a41dffbbaf3c81024f0a604a",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -535,7 +535,7 @@
}, },
"require-dev": { "require-dev": {
"phpstan/phpstan": "^1.10", "phpstan/phpstan": "^1.10",
"psr/log": "^1.0", "psr/log": "^1.0 || ^2.0 || ^3.0",
"symfony/phpunit-bridge": "^4.2 || ^5", "symfony/phpunit-bridge": "^4.2 || ^5",
"symfony/process": "^4.0 || ^5.0 || ^6.0 || ^7.0" "symfony/process": "^4.0 || ^5.0 || ^6.0 || ^7.0"
}, },
@ -572,7 +572,7 @@
"support": { "support": {
"irc": "irc://irc.freenode.org/composer", "irc": "irc://irc.freenode.org/composer",
"issues": "https://github.com/composer/ca-bundle/issues", "issues": "https://github.com/composer/ca-bundle/issues",
"source": "https://github.com/composer/ca-bundle/tree/1.5.0" "source": "https://github.com/composer/ca-bundle/tree/1.5.1"
}, },
"funding": [ "funding": [
{ {
@ -588,7 +588,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2024-03-15T14:00:32+00:00" "time": "2024-07-08T15:28:20+00:00"
}, },
{ {
"name": "doctrine/lexer", "name": "doctrine/lexer",
@ -976,22 +976,22 @@
}, },
{ {
"name": "guzzlehttp/guzzle", "name": "guzzlehttp/guzzle",
"version": "7.8.1", "version": "7.9.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/guzzle/guzzle.git", "url": "https://github.com/guzzle/guzzle.git",
"reference": "41042bc7ab002487b876a0683fc8dce04ddce104" "reference": "a629e5b69db96eb4939c1b34114130077dd4c6fc"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/41042bc7ab002487b876a0683fc8dce04ddce104", "url": "https://api.github.com/repos/guzzle/guzzle/zipball/a629e5b69db96eb4939c1b34114130077dd4c6fc",
"reference": "41042bc7ab002487b876a0683fc8dce04ddce104", "reference": "a629e5b69db96eb4939c1b34114130077dd4c6fc",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"ext-json": "*", "ext-json": "*",
"guzzlehttp/promises": "^1.5.3 || ^2.0.1", "guzzlehttp/promises": "^1.5.3 || ^2.0.3",
"guzzlehttp/psr7": "^1.9.1 || ^2.5.1", "guzzlehttp/psr7": "^2.7.0",
"php": "^7.2.5 || ^8.0", "php": "^7.2.5 || ^8.0",
"psr/http-client": "^1.0", "psr/http-client": "^1.0",
"symfony/deprecation-contracts": "^2.2 || ^3.0" "symfony/deprecation-contracts": "^2.2 || ^3.0"
@ -1002,9 +1002,9 @@
"require-dev": { "require-dev": {
"bamarni/composer-bin-plugin": "^1.8.2", "bamarni/composer-bin-plugin": "^1.8.2",
"ext-curl": "*", "ext-curl": "*",
"php-http/client-integration-tests": "dev-master#2c025848417c1135031fdf9c728ee53d0a7ceaee as 3.0.999", "guzzle/client-integration-tests": "3.0.2",
"php-http/message-factory": "^1.1", "php-http/message-factory": "^1.1",
"phpunit/phpunit": "^8.5.36 || ^9.6.15", "phpunit/phpunit": "^8.5.39 || ^9.6.20",
"psr/log": "^1.1 || ^2.0 || ^3.0" "psr/log": "^1.1 || ^2.0 || ^3.0"
}, },
"suggest": { "suggest": {
@ -1082,7 +1082,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/guzzle/guzzle/issues", "issues": "https://github.com/guzzle/guzzle/issues",
"source": "https://github.com/guzzle/guzzle/tree/7.8.1" "source": "https://github.com/guzzle/guzzle/tree/7.9.1"
}, },
"funding": [ "funding": [
{ {
@ -1098,20 +1098,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2023-12-03T20:35:24+00:00" "time": "2024-07-19T16:19:57+00:00"
}, },
{ {
"name": "guzzlehttp/promises", "name": "guzzlehttp/promises",
"version": "2.0.2", "version": "2.0.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/guzzle/promises.git", "url": "https://github.com/guzzle/promises.git",
"reference": "bbff78d96034045e58e13dedd6ad91b5d1253223" "reference": "6ea8dd08867a2a42619d65c3deb2c0fcbf81c8f8"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/guzzle/promises/zipball/bbff78d96034045e58e13dedd6ad91b5d1253223", "url": "https://api.github.com/repos/guzzle/promises/zipball/6ea8dd08867a2a42619d65c3deb2c0fcbf81c8f8",
"reference": "bbff78d96034045e58e13dedd6ad91b5d1253223", "reference": "6ea8dd08867a2a42619d65c3deb2c0fcbf81c8f8",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1119,7 +1119,7 @@
}, },
"require-dev": { "require-dev": {
"bamarni/composer-bin-plugin": "^1.8.2", "bamarni/composer-bin-plugin": "^1.8.2",
"phpunit/phpunit": "^8.5.36 || ^9.6.15" "phpunit/phpunit": "^8.5.39 || ^9.6.20"
}, },
"type": "library", "type": "library",
"extra": { "extra": {
@ -1165,7 +1165,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/guzzle/promises/issues", "issues": "https://github.com/guzzle/promises/issues",
"source": "https://github.com/guzzle/promises/tree/2.0.2" "source": "https://github.com/guzzle/promises/tree/2.0.3"
}, },
"funding": [ "funding": [
{ {
@ -1181,20 +1181,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2023-12-03T20:19:20+00:00" "time": "2024-07-18T10:29:17+00:00"
}, },
{ {
"name": "guzzlehttp/psr7", "name": "guzzlehttp/psr7",
"version": "2.6.2", "version": "2.7.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/guzzle/psr7.git", "url": "https://github.com/guzzle/psr7.git",
"reference": "45b30f99ac27b5ca93cb4831afe16285f57b8221" "reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/45b30f99ac27b5ca93cb4831afe16285f57b8221", "url": "https://api.github.com/repos/guzzle/psr7/zipball/a70f5c95fb43bc83f07c9c948baa0dc1829bf201",
"reference": "45b30f99ac27b5ca93cb4831afe16285f57b8221", "reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1209,8 +1209,8 @@
}, },
"require-dev": { "require-dev": {
"bamarni/composer-bin-plugin": "^1.8.2", "bamarni/composer-bin-plugin": "^1.8.2",
"http-interop/http-factory-tests": "^0.9", "http-interop/http-factory-tests": "0.9.0",
"phpunit/phpunit": "^8.5.36 || ^9.6.15" "phpunit/phpunit": "^8.5.39 || ^9.6.20"
}, },
"suggest": { "suggest": {
"laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses"
@ -1281,7 +1281,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/guzzle/psr7/issues", "issues": "https://github.com/guzzle/psr7/issues",
"source": "https://github.com/guzzle/psr7/tree/2.6.2" "source": "https://github.com/guzzle/psr7/tree/2.7.0"
}, },
"funding": [ "funding": [
{ {
@ -1297,7 +1297,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2023-12-03T20:05:35+00:00" "time": "2024-07-18T11:15:46+00:00"
}, },
{ {
"name": "jacklul/monolog-telegram", "name": "jacklul/monolog-telegram",
@ -1485,6 +1485,194 @@
}, },
"time": "2022-09-24T15:57:16+00:00" "time": "2022-09-24T15:57:16+00:00"
}, },
{
"name": "league/flysystem",
"version": "3.28.0",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/flysystem.git",
"reference": "e611adab2b1ae2e3072fa72d62c62f52c2bf1f0c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/flysystem/zipball/e611adab2b1ae2e3072fa72d62c62f52c2bf1f0c",
"reference": "e611adab2b1ae2e3072fa72d62c62f52c2bf1f0c",
"shasum": ""
},
"require": {
"league/flysystem-local": "^3.0.0",
"league/mime-type-detection": "^1.0.0",
"php": "^8.0.2"
},
"conflict": {
"async-aws/core": "<1.19.0",
"async-aws/s3": "<1.14.0",
"aws/aws-sdk-php": "3.209.31 || 3.210.0",
"guzzlehttp/guzzle": "<7.0",
"guzzlehttp/ringphp": "<1.1.1",
"phpseclib/phpseclib": "3.0.15",
"symfony/http-client": "<5.2"
},
"require-dev": {
"async-aws/s3": "^1.5 || ^2.0",
"async-aws/simple-s3": "^1.1 || ^2.0",
"aws/aws-sdk-php": "^3.295.10",
"composer/semver": "^3.0",
"ext-fileinfo": "*",
"ext-ftp": "*",
"ext-mongodb": "^1.3",
"ext-zip": "*",
"friendsofphp/php-cs-fixer": "^3.5",
"google/cloud-storage": "^1.23",
"guzzlehttp/psr7": "^2.6",
"microsoft/azure-storage-blob": "^1.1",
"mongodb/mongodb": "^1.2",
"phpseclib/phpseclib": "^3.0.36",
"phpstan/phpstan": "^1.10",
"phpunit/phpunit": "^9.5.11|^10.0",
"sabre/dav": "^4.6.0"
},
"type": "library",
"autoload": {
"psr-4": {
"League\\Flysystem\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Frank de Jonge",
"email": "info@frankdejonge.nl"
}
],
"description": "File storage abstraction for PHP",
"keywords": [
"WebDAV",
"aws",
"cloud",
"file",
"files",
"filesystem",
"filesystems",
"ftp",
"s3",
"sftp",
"storage"
],
"support": {
"issues": "https://github.com/thephpleague/flysystem/issues",
"source": "https://github.com/thephpleague/flysystem/tree/3.28.0"
},
"time": "2024-05-22T10:09:12+00:00"
},
{
"name": "league/flysystem-local",
"version": "3.28.0",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/flysystem-local.git",
"reference": "13f22ea8be526ea58c2ddff9e158ef7c296e4f40"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/flysystem-local/zipball/13f22ea8be526ea58c2ddff9e158ef7c296e4f40",
"reference": "13f22ea8be526ea58c2ddff9e158ef7c296e4f40",
"shasum": ""
},
"require": {
"ext-fileinfo": "*",
"league/flysystem": "^3.0.0",
"league/mime-type-detection": "^1.0.0",
"php": "^8.0.2"
},
"type": "library",
"autoload": {
"psr-4": {
"League\\Flysystem\\Local\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Frank de Jonge",
"email": "info@frankdejonge.nl"
}
],
"description": "Local filesystem adapter for Flysystem.",
"keywords": [
"Flysystem",
"file",
"files",
"filesystem",
"local"
],
"support": {
"source": "https://github.com/thephpleague/flysystem-local/tree/3.28.0"
},
"time": "2024-05-06T20:05:52+00:00"
},
{
"name": "league/mime-type-detection",
"version": "1.15.0",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/mime-type-detection.git",
"reference": "ce0f4d1e8a6f4eb0ddff33f57c69c50fd09f4301"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/ce0f4d1e8a6f4eb0ddff33f57c69c50fd09f4301",
"reference": "ce0f4d1e8a6f4eb0ddff33f57c69c50fd09f4301",
"shasum": ""
},
"require": {
"ext-fileinfo": "*",
"php": "^7.4 || ^8.0"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.2",
"phpstan/phpstan": "^0.12.68",
"phpunit/phpunit": "^8.5.8 || ^9.3 || ^10.0"
},
"type": "library",
"autoload": {
"psr-4": {
"League\\MimeTypeDetection\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Frank de Jonge",
"email": "info@frankdejonge.nl"
}
],
"description": "Mime-type detection for Flysystem",
"support": {
"issues": "https://github.com/thephpleague/mime-type-detection/issues",
"source": "https://github.com/thephpleague/mime-type-detection/tree/1.15.0"
},
"funding": [
{
"url": "https://github.com/frankdejonge",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/league/flysystem",
"type": "tidelift"
}
],
"time": "2024-01-28T23:22:08+00:00"
},
{ {
"name": "longman/ip-tools", "name": "longman/ip-tools",
"version": "1.2.1", "version": "1.2.1",
@ -1545,6 +1733,106 @@
}, },
"time": "2016-10-23T20:08:46+00:00" "time": "2016-10-23T20:08:46+00:00"
}, },
{
"name": "matthiasmullie/scrapbook",
"version": "1.5.3",
"source": {
"type": "git",
"url": "https://github.com/matthiasmullie/scrapbook.git",
"reference": "c339d56e136713aab532718eff453663b4b38efe"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/matthiasmullie/scrapbook/zipball/c339d56e136713aab532718eff453663b4b38efe",
"reference": "c339d56e136713aab532718eff453663b4b38efe",
"shasum": ""
},
"require": {
"php": ">=8.0.0",
"psr/cache": "^2.0||^3.0",
"psr/simple-cache": "^2.0||^3.0"
},
"provide": {
"psr/cache-implementation": "^1.0||^2.0||^3.0",
"psr/simple-cache-implementation": "^1.0||^2.0||^3.0"
},
"require-dev": {
"ext-pcntl": "*",
"friendsofphp/php-cs-fixer": ">=2.0",
"phpunit/phpunit": ">=10.0",
"squizlabs/php_codesniffer": ">=3.0"
},
"suggest": {
"couchbase/couchbase": ">=3.0",
"ext-apcu": ">=4.0.0",
"ext-couchbase": ">=3.0.0",
"ext-memcached": ">=2.0.0",
"ext-pdo": ">=0.1.0",
"ext-redis": ">=2.2.0||0.0.0.0",
"league/flysystem": ">=1.0"
},
"type": "library",
"autoload": {
"psr-4": {
"MatthiasMullie\\Scrapbook\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Matthias Mullie",
"email": "scrapbook@mullie.eu",
"homepage": "https://www.mullie.eu",
"role": "Developer"
}
],
"description": "Scrapbook is a PHP cache library, with adapters for e.g. Memcached, Redis, Couchbase, APCu, SQL and additional capabilities (e.g. transactions, stampede protection) built on top.",
"homepage": "https://scrapbook.cash",
"keywords": [
"Buffer",
"Flysystem",
"apc",
"buffered",
"cache",
"caching",
"commit",
"couchbase",
"filesystem",
"key",
"memcached",
"mitigation",
"mysql",
"postgresql",
"protection",
"psr-16",
"psr-6",
"psr-cache",
"psr-simple-cache",
"redis",
"rollback",
"sql",
"sqlite",
"stampede",
"store",
"transaction",
"transactional",
"value"
],
"support": {
"issues": "https://github.com/matthiasmullie/scrapbook/issues",
"source": "https://github.com/matthiasmullie/scrapbook/tree/1.5.3"
},
"funding": [
{
"url": "https://github.com/matthiasmullie",
"type": "github"
}
],
"time": "2024-04-02T13:33:01+00:00"
},
{ {
"name": "monolog/monolog", "name": "monolog/monolog",
"version": "3.7.0", "version": "3.7.0",
@ -1852,6 +2140,55 @@
], ],
"time": "2024-07-20T21:41:07+00:00" "time": "2024-07-20T21:41:07+00:00"
}, },
{
"name": "psr/cache",
"version": "3.0.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/cache.git",
"reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/cache/zipball/aa5030cfa5405eccfdcb1083ce040c2cb8d253bf",
"reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf",
"shasum": ""
},
"require": {
"php": ">=8.0.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Cache\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "https://www.php-fig.org/"
}
],
"description": "Common interface for caching libraries",
"keywords": [
"cache",
"psr",
"psr-6"
],
"support": {
"source": "https://github.com/php-fig/cache/tree/3.0.0"
},
"time": "2021-02-03T23:26:27+00:00"
},
{ {
"name": "psr/container", "name": "psr/container",
"version": "2.0.2", "version": "2.0.2",
@ -2165,6 +2502,57 @@
}, },
"time": "2021-07-14T16:46:02+00:00" "time": "2021-07-14T16:46:02+00:00"
}, },
{
"name": "psr/simple-cache",
"version": "3.0.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/simple-cache.git",
"reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/simple-cache/zipball/764e0b3939f5ca87cb904f570ef9be2d78a07865",
"reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865",
"shasum": ""
},
"require": {
"php": ">=8.0.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\SimpleCache\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "https://www.php-fig.org/"
}
],
"description": "Common interfaces for simple caching",
"keywords": [
"cache",
"caching",
"psr",
"psr-16",
"simple-cache"
],
"support": {
"source": "https://github.com/php-fig/simple-cache/tree/3.0.0"
},
"time": "2021-10-29T13:26:27+00:00"
},
{ {
"name": "ralouphie/getallheaders", "name": "ralouphie/getallheaders",
"version": "3.0.3", "version": "3.0.3",
@ -3679,5 +4067,5 @@
"php": "^8.1" "php": "^8.1"
}, },
"platform-dev": [], "platform-dev": [],
"plugin-api-version": "2.6.0" "plugin-api-version": "2.3.0"
} }

View file

@ -647,9 +647,6 @@ VALUES ('1', 'Attach maintenance', 'attach_maintenance.php', 'daily', '', '05:00
'', '0', '0', '0'), '', '0', '0', '0'),
('1', 'Tracker dl-complete count', 'tr_complete_count.php', 'interval', '', '', '255', '', '', '06:00:00', '0', ('1', 'Tracker dl-complete count', 'tr_complete_count.php', 'interval', '', '', '255', '', '', '06:00:00', '0',
'', '0', '0', '0'), '', '0', '0', '0'),
('1', 'Cache garbage collector', 'cache_gc.php', 'interval', '', '', '255', '', '', '00:05:00', '0', '', '0',
'0',
'0'),
('1', 'Sitemap update', 'sitemap.php', 'daily', '', '06:00:00', '30', '', '', '', '0', '', '0', '0', '0'), ('1', 'Sitemap update', 'sitemap.php', 'daily', '', '06:00:00', '30', '', '', '', '0', '', '0', '0', '0'),
('1', 'Update forums atom', 'update_forums_atom.php', 'interval', '', '', '255', '', '', '00:15:00', '0', '', ('1', 'Update forums atom', 'update_forums_atom.php', 'interval', '', '', '255', '', '', '00:15:00', '0', '',
'0', '0',

View file

@ -54,36 +54,32 @@ $bb_cfg['db_alias'] = [
// Cache // Cache
$bb_cfg['cache'] = [ $bb_cfg['cache'] = [
'pconnect' => true,
'db_dir' => realpath(BB_ROOT) . '/internal_data/cache/filecache/', 'db_dir' => realpath(BB_ROOT) . '/internal_data/cache/filecache/',
'prefix' => 'tp_', 'prefix' => 'tp_',
'memcache' => [ 'memcached' => [
'host' => '127.0.0.1', 'host' => '127.0.0.1',
'port' => 11211, 'port' => 11211,
'pconnect' => true,
'con_required' => true,
], ],
'redis' => [ 'redis' => [
'host' => '127.0.0.1', 'host' => '127.0.0.1',
'port' => 6379, 'port' => 6379,
'pconnect' => !PHP_ZTS, // Redis pconnect supported only for non-thread safe compilations of PHP 'pconnect' => !PHP_ZTS, // Redis pconnect supported only for non-thread safe compilations of PHP
'con_required' => true,
], ],
// Available cache types: filecache, memcache, sqlite, redis, apcu (filecache by default) // Available cache types: filecache, memcached, sqlite, redis, apcu (filecache by default)
'engines' => [ 'engines' => [
'bb_cache' => ['filecache', []], 'bb_cache' => ['filecache'],
'bb_config' => ['filecache', []], 'bb_config' => ['filecache'],
'tr_cache' => ['filecache', []], 'tr_cache' => ['filecache'],
'session_cache' => ['filecache', []], 'session_cache' => ['filecache'],
'bb_cap_sid' => ['filecache', []], 'bb_cap_sid' => ['filecache'],
'bb_login_err' => ['filecache', []], 'bb_login_err' => ['filecache'],
'bb_poll_data' => ['filecache', []], 'bb_poll_data' => ['filecache'],
'bb_ip2countries' => ['filecache', []], 'bb_ip2countries' => ['filecache'],
], ],
]; ];
// Datastore // Datastore
// Available datastore types: filecache, memcache, sqlite, redis, apcu (filecache by default) // Available datastore types: filecache, memcached, sqlite, redis, apcu (filecache by default)
$bb_cfg['datastore_type'] = 'filecache'; $bb_cfg['datastore_type'] = 'filecache';
// Server // Server

View file

@ -1,21 +0,0 @@
<?php
/**
* TorrentPier Bull-powered BitTorrent tracker engine
*
* @copyright Copyright (c) 2005-2024 TorrentPier (https://torrentpier.com)
* @link https://github.com/torrentpier/torrentpier for the canonical source repository
* @license https://github.com/torrentpier/torrentpier/blob/master/LICENSE MIT License
*/
if (!defined('BB_ROOT')) {
die(basename(__FILE__));
}
global $cron_runtime_log;
foreach ($bb_cfg['cache']['engines'] as $cache_name => $cache_val) {
if (method_exists(CACHE($cache_name), 'gc')) {
$changes = CACHE($cache_name)->gc();
$cron_runtime_log[] = date('Y-m-d H:i:s') . " -- " . str_pad("$cache_name ", 25, '-', STR_PAD_RIGHT) . " del: $changes";
}
}

View file

@ -9,72 +9,122 @@
namespace TorrentPier\Legacy\Cache; namespace TorrentPier\Legacy\Cache;
use MatthiasMullie\Scrapbook\Adapters\Apc;
/** /**
* Class APCu * Class APCu
* @package TorrentPier\Legacy\Cache * @package TorrentPier\Legacy\Cache
*/ */
class APCu extends Common class APCu extends Common
{ {
public $used = true; /**
public $engine = 'APCu'; * Currently in usage
public $prefix; *
* @var bool
*/
public bool $used = true;
public function __construct($prefix = null) /**
* Cache driver name
*
* @var string
*/
public string $engine = 'APCu';
/**
* Cache prefix
*
* @var string
*/
private string $prefix;
/**
* Adapters\Apc class
*
* @var Apc
*/
private Apc $apcu;
/**
* APCu constructor
*
* @param string $prefix
*/
public function __construct(string $prefix)
{ {
global $debug; global $debug;
if (!$this->is_installed()) { $this->apcu = new Apc();
die("Error: $this->engine extension not installed");
}
$this->prefix = $prefix; $this->prefix = $prefix;
$this->dbg_enabled = $debug->sqlDebugAllowed(); $this->dbg_enabled = $debug->sqlDebugAllowed();
} }
public function get($name, $get_miss_key_callback = '', $ttl = 0) /**
* Fetch data from cache
*
* @param string $name
* @return mixed
*/
public function get(string $name): mixed
{ {
$this->cur_query = "cache->get('$name')"; $name = $this->prefix . $name;
$this->cur_query = "cache->" . __FUNCTION__ . "('$name')";
$this->debug('start'); $this->debug('start');
$result = $this->apcu->get($name);
$this->debug('stop'); $this->debug('stop');
$this->cur_query = null; $this->cur_query = null;
$this->num_queries++; $this->num_queries++;
return apcu_fetch($this->prefix . $name); return $result;
} }
public function set($name, $value, $ttl = 0) /**
* Store data into cache
*
* @param string $name
* @param mixed $value
* @param int $ttl
* @return bool
*/
public function set(string $name, mixed $value, int $ttl = 0): bool
{ {
$this->cur_query = "cache->set('$name')"; $name = $this->prefix . $name;
$this->cur_query = "cache->" . __FUNCTION__ . "('$name')";
$this->debug('start'); $this->debug('start');
if (apcu_store($this->prefix . $name, $value, $ttl)) { $result = $this->apcu->set($name, $value, $ttl);
$this->debug('stop'); $this->debug('stop');
$this->cur_query = null; $this->cur_query = null;
$this->num_queries++; $this->num_queries++;
return true; return $result;
} }
return false; /**
} * Removes data from cache
*
public function rm($name = '') * @param string|null $name
* @return bool
*/
public function rm(string $name = null): bool
{ {
if ($name) { $targetMethod = is_string($name) ? 'delete' : 'flush';
$this->cur_query = "cache->rm('$name')"; $name = is_string($name) ? ("'" . $this->prefix . $name . "'") : null;
$this->cur_query = "cache->$targetMethod($name)";
$this->debug('start'); $this->debug('start');
$result = $this->apcu->$targetMethod($name);
$this->debug('stop'); $this->debug('stop');
$this->cur_query = null; $this->cur_query = null;
$this->num_queries++; $this->num_queries++;
return apcu_delete($this->prefix . $name); return $result;
}
return apcu_clear_cache();
}
public function is_installed(): bool
{
return extension_loaded('apcu') && apcu_enabled();
} }
} }

View file

@ -15,31 +15,44 @@ namespace TorrentPier\Legacy\Cache;
*/ */
class Common class Common
{ {
public $used = false; /**
* Currently in usage
*
* @var bool
*/
public bool $used = true;
/** /**
* Returns value of variable * Fetch data from cache
*
* @param string $name
* @return mixed
*/ */
public function get($name, $get_miss_key_callback = '', $ttl = 604800) public function get(string $name): mixed
{
if ($get_miss_key_callback) {
return $get_miss_key_callback($name);
}
return \is_array($name) ? [] : false;
}
/**
* Store value of variable
*/
public function set($name, $value, $ttl = 604800)
{ {
return false; return false;
} }
/** /**
* Remove variable * Store data into cache
*
* @param string $name
* @param mixed $value
* @param int $ttl
* @return bool
*/ */
public function rm($name = '') public function set(string $name, mixed $value, int $ttl = 604800): bool
{
return false;
}
/**
* Removes data from cache
*
* @param string|null $name
* @return bool
*/
public function rm(string $name = null): bool
{ {
return false; return false;
} }

View file

@ -9,125 +9,127 @@
namespace TorrentPier\Legacy\Cache; namespace TorrentPier\Legacy\Cache;
use League\Flysystem\Filesystem;
use League\Flysystem\Local\LocalFilesystemAdapter;
use MatthiasMullie\Scrapbook\Adapters\Flysystem;
/** /**
* Class File * Class File
* @package TorrentPier\Legacy\Cache * @package TorrentPier\Legacy\Cache
*/ */
class File extends Common class File extends Common
{ {
public $used = true; /**
public $engine = 'Filecache'; * Currently in usage
public $dir; *
public $prefix; * @var bool
*/
public bool $used = true;
public function __construct($dir, $prefix = null) /**
* Cache driver name
*
* @var string
*/
public string $engine = 'File';
/**
* Cache prefix
*
* @var string
*/
private string $prefix;
/**
* Adapters\File class
*
* @var Flysystem
*/
private Flysystem $file;
/**
* File constructor
*
* @param string $dir
* @param string $prefix
*/
public function __construct(string $dir, string $prefix)
{ {
global $debug; global $debug;
$this->dir = $dir; $adapter = new LocalFilesystemAdapter($dir, null, LOCK_EX);
$filesystem = new Filesystem($adapter);
$this->file = new Flysystem($filesystem);
$this->prefix = $prefix; $this->prefix = $prefix;
$this->dbg_enabled = $debug->sqlDebugAllowed(); $this->dbg_enabled = $debug->sqlDebugAllowed();
} }
public function get($name, $get_miss_key_callback = '', $ttl = 0) /**
* Fetch data from cache
*
* @param string $name
* @return mixed
*/
public function get(string $name): mixed
{ {
$filecache = []; $name = $this->prefix . $name;
$filename = $this->dir . clean_filename($this->prefix . $name) . '.php';
$this->cur_query = "cache->get('$name')"; $this->cur_query = "cache->" . __FUNCTION__ . "('$name')";
$this->debug('start'); $this->debug('start');
if (is_file($filename) && is_readable($filename)) { $result = $this->file->get($name);
require($filename);
}
$this->debug('stop');
$this->cur_query = null;
return (!empty($filecache['value'])) ? $filecache['value'] : false;
}
public function set($name, $value, $ttl = 86400)
{
if (!\function_exists('var_export')) {
return false;
}
$this->cur_query = "cache->set('$name')";
$this->debug('start');
$filename = $this->dir . clean_filename($this->prefix . $name) . '.php';
$expire = TIMENOW + $ttl;
$cache_data = ['expire' => $expire, 'value' => $value];
$filecache = "<?php\n";
$filecache .= "if (!defined('BB_ROOT')) die(basename(__FILE__));\n";
$filecache .= '$filecache = ' . var_export($cache_data, true) . ";\n";
$filecache .= '?>';
$this->debug('stop'); $this->debug('stop');
$this->cur_query = null; $this->cur_query = null;
$this->num_queries++; $this->num_queries++;
return (bool)file_write($filecache, $filename, max_size: false, replace_content: true); return $result;
} }
public function rm($name = '') /**
* Store data into cache
*
* @param string $name
* @param mixed $value
* @param int $ttl
* @return bool
*/
public function set(string $name, mixed $value, int $ttl = 0): bool
{ {
$clear = false; $name = $this->prefix . $name;
if ($name) {
$this->cur_query = "cache->rm('$name')"; $this->cur_query = "cache->" . __FUNCTION__ . "('$name')";
$this->debug('start'); $this->debug('start');
$filename = $this->dir . clean_filename($this->prefix . $name) . '.php'; $result = $this->file->set($name, $value, $ttl);
if (is_file($filename)) {
$clear = (bool)unlink($filename);
}
$this->debug('stop'); $this->debug('stop');
$this->cur_query = null; $this->cur_query = null;
$this->num_queries++; $this->num_queries++;
} else {
if (is_dir($this->dir)) {
if ($dh = opendir($this->dir)) {
while (($file = readdir($dh)) !== false) {
if ($file != "." && $file != "..") {
$filename = $this->dir . $file;
unlink($filename); return $result;
$clear = true;
}
}
closedir($dh);
}
}
}
return $clear;
} }
public function gc($expire_time = TIMENOW) /**
* Removes data from cache
*
* @param string|null $name
* @return bool
*/
public function rm(string $name = null): bool
{ {
$filecache = []; $targetMethod = is_string($name) ? 'delete' : 'flush';
$clear = false; $name = is_string($name) ? ("'" . $this->prefix . $name . "'") : null;
if (is_dir($this->dir)) { $this->cur_query = "cache->$targetMethod($name)";
if ($dh = opendir($this->dir)) { $this->debug('start');
while (($file = readdir($dh)) !== false) {
if ($file != "." && $file != "..") {
$filename = $this->dir . $file;
require($filename); $result = $this->file->$targetMethod($name);
if (!empty($filecache['expire']) && ($filecache['expire'] < $expire_time)) { $this->debug('stop');
unlink($filename); $this->cur_query = null;
$clear = true; $this->num_queries++;
}
}
}
closedir($dh);
}
}
return $clear; return $result;
} }
} }

View file

@ -1,111 +0,0 @@
<?php
/**
* TorrentPier Bull-powered BitTorrent tracker engine
*
* @copyright Copyright (c) 2005-2024 TorrentPier (https://torrentpier.com)
* @link https://github.com/torrentpier/torrentpier for the canonical source repository
* @license https://github.com/torrentpier/torrentpier/blob/master/LICENSE MIT License
*/
namespace TorrentPier\Legacy\Cache;
/**
* Class Memcache
* @package TorrentPier\Legacy\Cache
*/
class Memcache extends Common
{
public $used = true;
public $engine = 'Memcache';
public $cfg;
public $prefix;
public $memcache;
public $connected = false;
public function __construct($cfg, $prefix = null)
{
global $debug;
if (!$this->is_installed()) {
die("Error: $this->engine extension not installed");
}
$this->cfg = $cfg;
$this->prefix = $prefix;
$this->memcache = new \Memcache();
$this->dbg_enabled = $debug->sqlDebugAllowed();
}
public function connect()
{
$connect_type = ($this->cfg['pconnect']) ? 'pconnect' : 'connect';
$this->cur_query = $connect_type . ' ' . $this->cfg['host'] . ':' . $this->cfg['port'];
$this->debug('start');
if (@$this->memcache->$connect_type($this->cfg['host'], $this->cfg['port'])) {
$this->connected = true;
}
if (!$this->connected && $this->cfg['con_required']) {
die("Could not connect to $this->engine server");
}
$this->debug('stop');
$this->cur_query = null;
}
public function get($name, $get_miss_key_callback = '', $ttl = 0)
{
if (!$this->connected) {
$this->connect();
}
$this->cur_query = "cache->get('$name')";
$this->debug('start');
$this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
return ($this->connected) ? $this->memcache->get($this->prefix . $name) : false;
}
public function set($name, $value, $ttl = 0)
{
if (!$this->connected) {
$this->connect();
}
$this->cur_query = "cache->set('$name')";
$this->debug('start');
$this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
return ($this->connected) ? $this->memcache->set($this->prefix . $name, $value, false, $ttl) : false;
}
public function rm($name = '')
{
if (!$this->connected) {
$this->connect();
}
if ($name) {
$this->cur_query = "cache->rm('$name')";
$this->debug('start');
$this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
return ($this->connected) ? $this->memcache->delete($this->prefix . $name, 0) : false;
}
return ($this->connected) ? $this->memcache->flush() : false;
}
public function is_installed()
{
return class_exists('Memcache');
}
}

View file

@ -0,0 +1,190 @@
<?php
/**
* TorrentPier Bull-powered BitTorrent tracker engine
*
* @copyright Copyright (c) 2005-2024 TorrentPier (https://torrentpier.com)
* @link https://github.com/torrentpier/torrentpier for the canonical source repository
* @license https://github.com/torrentpier/torrentpier/blob/master/LICENSE MIT License
*/
namespace TorrentPier\Legacy\Cache;
use Memcached as MemcachedClient;
use MatthiasMullie\Scrapbook\Adapters\Memcached as MemcachedCache;
/**
* Class Memcached
* @package TorrentPier\Legacy\Cache
*/
class Memcached extends Common
{
/**
* Currently in usage
*
* @var bool
*/
public bool $used = true;
/**
* Connection status
*
* @var bool
*/
public bool $connected = false;
/**
* Cache driver name
*
* @var string
*/
public string $engine = 'Memcached';
/**
* Cache config
*
* @var array
*/
private array $cfg;
/**
* Cache prefix
*
* @var string
*/
private string $prefix;
/**
* Memcached class
*
* @var MemcachedClient
*/
private MemcachedClient $client;
/**
* Adapters\Memcached class
*
* @var MemcachedCache
*/
private MemcachedCache $memcached;
/**
* Memcached constructor
*
* @param array $cfg
* @param string $prefix
*/
public function __construct(array $cfg, string $prefix)
{
global $debug;
$this->client = new MemcachedClient();
$this->cfg = $cfg;
$this->prefix = $prefix;
$this->dbg_enabled = $debug->sqlDebugAllowed();
}
/**
* Connect to cache
*
* @return void
*/
private function connect(): void
{
$this->cur_query = 'connect ' . $this->cfg['host'] . ':' . $this->cfg['port'];
$this->debug('start');
if ($this->client->addServer($this->cfg['host'], $this->cfg['port'])) {
$this->connected = true;
}
if (!$this->connected) {
die("Could not connect to $this->engine server");
}
$this->memcached = new MemcachedCache($this->client);
$this->debug('stop');
$this->cur_query = null;
}
/**
* Fetch data from cache
*
* @param string $name
* @return mixed
*/
public function get(string $name): mixed
{
if (!$this->connected) {
$this->connect();
}
$name = $this->prefix . $name;
$this->cur_query = "cache->" . __FUNCTION__ . "('$name')";
$this->debug('start');
$result = $this->memcached->get($name);
$this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
return $result;
}
/**
* Store data into cache
*
* @param string $name
* @param mixed $value
* @param int $ttl
* @return bool
*/
public function set(string $name, mixed $value, int $ttl = 0): bool
{
if (!$this->connected) {
$this->connect();
}
$name = $this->prefix . $name;
$this->cur_query = "cache->" . __FUNCTION__ . "('$name')";
$this->debug('start');
$result = $this->memcached->set($name, $value, $ttl);
$this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
return $result;
}
/**
* Removes data from cache
*
* @param string|null $name
* @return bool
*/
public function rm(string $name = null): bool
{
if (!$this->connected) {
$this->connect();
}
$targetMethod = is_string($name) ? 'delete' : 'flush';
$name = is_string($name) ? ("'" . $this->prefix . $name . "'") : null;
$this->cur_query = "cache->$targetMethod($name)";
$this->debug('start');
$result = $this->memcached->$targetMethod($name);
$this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
return $result;
}
}

View file

@ -9,112 +9,184 @@
namespace TorrentPier\Legacy\Cache; namespace TorrentPier\Legacy\Cache;
use Redis as RedisClient;
use MatthiasMullie\Scrapbook\Adapters\Redis as RedisCache;
/** /**
* Class Redis * Class Redis
* @package TorrentPier\Legacy\Cache * @package TorrentPier\Legacy\Cache
*/ */
class Redis extends Common class Redis extends Common
{ {
public $used = true; /**
public $engine = 'Redis'; * Currently in usage
public $cfg; *
public $redis; * @var bool
public $prefix; */
public $connected = false; public bool $used = true;
public function __construct($cfg, $prefix = null) /**
* Connection status
*
* @var bool
*/
public bool $connected = false;
/**
* Cache driver name
*
* @var string
*/
public string $engine = 'Redis';
/**
* Cache config
*
* @var array
*/
private array $cfg;
/**
* Cache prefix
*
* @var string
*/
private string $prefix;
/**
* Redis class
*
* @var RedisClient
*/
private RedisClient $client;
/**
* Adapters\Redis class
*
* @var RedisCache
*/
private RedisCache $redis;
/**
* Redis constructor
*
* @param array $cfg
* @param string $prefix
*/
public function __construct(array $cfg, string $prefix)
{ {
global $debug; global $debug;
if (!$this->is_installed()) { $this->client = new RedisClient();
die("Error: $this->engine extension not installed");
}
$this->cfg = $cfg; $this->cfg = $cfg;
$this->prefix = $prefix; $this->prefix = $prefix;
$this->redis = new \Redis();
$this->dbg_enabled = $debug->sqlDebugAllowed(); $this->dbg_enabled = $debug->sqlDebugAllowed();
} }
public function connect() /**
* Connect to cache
*
* @return void
*/
private function connect(): void
{ {
$connect_type = ($this->cfg['pconnect']) ? 'pconnect' : 'connect'; $connectType = $this->cfg['pconnect'] ? 'pconnect' : 'connect';
$this->cur_query = $connect_type . ' ' . $this->cfg['host'] . ':' . $this->cfg['port']; $this->cur_query = $connectType . ' ' . $this->cfg['host'] . ':' . $this->cfg['port'];
$this->debug('start'); $this->debug('start');
if (@$this->redis->$connect_type($this->cfg['host'], $this->cfg['port'])) { if ($this->client->$connectType($this->cfg['host'], $this->cfg['port'])) {
$this->connected = true; $this->connected = true;
} }
if (!$this->connected && $this->cfg['con_required']) { if (!$this->connected) {
die("Could not connect to $this->engine server"); die("Could not connect to $this->engine server");
} }
$this->redis = new RedisCache($this->client);
$this->debug('stop'); $this->debug('stop');
$this->cur_query = null; $this->cur_query = null;
} }
public function get($name, $get_miss_key_callback = '', $ttl = 0) /**
* Fetch data from cache
*
* @param string $name
* @return mixed
*/
public function get(string $name): mixed
{ {
if (!$this->connected) { if (!$this->connected) {
$this->connect(); $this->connect();
} }
$this->cur_query = "cache->get('$name')"; $name = $this->prefix . $name;
$this->cur_query = "cache->" . __FUNCTION__ . "('$name')";
$this->debug('start'); $this->debug('start');
$result = $this->redis->get($name);
$this->debug('stop'); $this->debug('stop');
$this->cur_query = null; $this->cur_query = null;
$this->num_queries++; $this->num_queries++;
return ($this->connected) ? unserialize($this->redis->get($this->prefix . $name)) : false; return $result;
} }
public function set($name, $value, $ttl = 0) /**
* Store data into cache
*
* @param string $name
* @param mixed $value
* @param int $ttl
* @return bool
*/
public function set(string $name, mixed $value, int $ttl = 0): bool
{ {
if (!$this->connected) { if (!$this->connected) {
$this->connect(); $this->connect();
} }
$this->cur_query = "cache->set('$name')"; $name = $this->prefix . $name;
$this->cur_query = "cache->" . __FUNCTION__ . "('$name')";
$this->debug('start'); $this->debug('start');
if ($this->redis->set($this->prefix . $name, serialize($value))) { $result = $this->redis->set($name, $value, $ttl);
if ($ttl > 0) {
$this->redis->expire($this->prefix . $name, $ttl);
}
$this->debug('stop'); $this->debug('stop');
$this->cur_query = null; $this->cur_query = null;
$this->num_queries++; $this->num_queries++;
return true; return $result;
} }
return false; /**
} * Removes data from cache
*
public function rm($name = '') * @param string|null $name
* @return bool
*/
public function rm(string $name = null): bool
{ {
if (!$this->connected) { if (!$this->connected) {
$this->connect(); $this->connect();
} }
if ($name) { $targetMethod = is_string($name) ? 'delete' : 'flush';
$this->cur_query = "cache->rm('$name')"; $name = is_string($name) ? ("'" . $this->prefix . $name . "'") : null;
$this->cur_query = "cache->$targetMethod($name)";
$this->debug('start'); $this->debug('start');
$result = $this->redis->$targetMethod($name);
$this->debug('stop'); $this->debug('stop');
$this->cur_query = null; $this->cur_query = null;
$this->num_queries++; $this->num_queries++;
return ($this->connected) ? $this->redis->del($this->prefix . $name) : false; return $result;
}
return ($this->connected) ? $this->redis->flushDB() : false;
}
public function is_installed()
{
return class_exists('Redis');
} }
} }

View file

@ -9,7 +9,8 @@
namespace TorrentPier\Legacy\Cache; namespace TorrentPier\Legacy\Cache;
use SQLite3; use MatthiasMullie\Scrapbook\Adapters\SQLite as SQLiteCache;
use PDO;
/** /**
* Class Sqlite * Class Sqlite
@ -17,107 +18,116 @@ use SQLite3;
*/ */
class Sqlite extends Common class Sqlite extends Common
{ {
public $used = true; /**
public $db; * Currently in usage
public $prefix; *
public $engine = 'SQLite'; * @var bool
public $cfg = [ */
'db_file_path' => '/path/to/cache.db.sqlite', public bool $used = true;
'table_name' => 'cache',
'table_schema' => 'CREATE TABLE cache (
cache_name VARCHAR(255),
cache_expire_time INT,
cache_value TEXT,
PRIMARY KEY (cache_name)
)',
'pconnect' => true,
'con_required' => true,
'log_name' => 'CACHE',
];
public function __construct($cfg, $prefix = null) /**
* Cache driver name
*
* @var string
*/
public string $engine = 'SQLite';
/**
* Cache prefix
*
* @var string
*/
private string $prefix;
/**
* Adapters\SQLite class
*
* @var SQLiteCache
*/
private SQLiteCache $sqlite;
/**
* Sqlite constructor
*
* @param string $dir
* @param string $prefix
*/
public function __construct(string $dir, string $prefix)
{ {
if (!$this->is_installed()) { global $debug;
die('Error: SQLite3 extension not installed');
}
$this->cfg = array_merge($this->cfg, $cfg); $client = new PDO("sqlite:$dir.db");
$this->db = new SqliteCommon($this->cfg); $this->sqlite = new SQLiteCache($client);
$this->prefix = $prefix; $this->prefix = $prefix;
$this->dbg_enabled = $debug->sqlDebugAllowed();
} }
public function get($name, $get_miss_key_callback = '', $ttl = 604800) /**
* Fetch data from cache
*
* @param string $name
* @return mixed
*/
public function get(string $name): mixed
{ {
if (empty($name)) { $name = $this->prefix . $name;
return \is_array($name) ? [] : false;
}
$this->db->shard($name);
$cached_items = [];
$prefix_len = \strlen($this->prefix);
$prefix_sql = SQLite3::escapeString($this->prefix);
$name_ary = $name_sql = (array)$name; $this->cur_query = "cache->" . __FUNCTION__ . "('$name')";
array_deep($name_sql, 'SQLite3::escapeString'); $this->debug('start');
// get available items $result = $this->sqlite->get($name);
$rowset = $this->db->fetch_rowset("
SELECT cache_name, cache_value
FROM " . $this->cfg['table_name'] . "
WHERE cache_name IN('$prefix_sql" . implode("','$prefix_sql", $name_sql) . "') AND cache_expire_time > " . TIMENOW . "
LIMIT " . \count($name_sql) . "
");
$this->db->debug('start', 'unserialize()'); $this->debug('stop');
foreach ($rowset as $row) { $this->cur_query = null;
$cached_items[substr($row['cache_name'], $prefix_len)] = unserialize($row['cache_value']); $this->num_queries++;
}
$this->db->debug('stop');
// get miss items return $result;
if ($get_miss_key_callback and $miss_key = array_diff($name_ary, array_keys($cached_items))) {
foreach ($get_miss_key_callback($miss_key) as $k => $v) {
$this->set($this->prefix . $k, $v, $ttl);
$cached_items[$k] = $v;
}
}
// return
if (\is_array($this->prefix . $name)) {
return $cached_items;
} }
return $cached_items[$name] ?? false; /**
} * Store data into cache
*
public function set($name, $value, $ttl = 604800) * @param string $name
* @param mixed $value
* @param int $ttl
* @return bool
*/
public function set(string $name, mixed $value, int $ttl = 0): bool
{ {
$this->db->shard($this->prefix . $name); $name = $this->prefix . $name;
$name_sql = SQLite3::escapeString($this->prefix . $name);
$expire = TIMENOW + $ttl;
$value_sql = SQLite3::escapeString(serialize($value));
$result = $this->db->query("REPLACE INTO " . $this->cfg['table_name'] . " (cache_name, cache_expire_time, cache_value) VALUES ('$name_sql', $expire, '$value_sql')"); $this->cur_query = "cache->" . __FUNCTION__ . "('$name')";
return (bool)$result; $this->debug('start');
$result = $this->sqlite->set($name, $value, $ttl);
$this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
return $result;
} }
public function rm($name = '') /**
* Removes data from cache
*
* @param string|null $name
* @return bool
*/
public function rm(string $name = null): bool
{ {
if ($name) { $targetMethod = is_string($name) ? 'delete' : 'flush';
$this->db->shard($this->prefix . $name); $name = is_string($name) ? ("'" . $this->prefix . $name . "'") : null;
$result = $this->db->query("DELETE FROM " . $this->cfg['table_name'] . " WHERE cache_name = '" . SQLite3::escapeString($this->prefix . $name) . "'");
} else {
$result = $this->db->query("DELETE FROM " . $this->cfg['table_name']);
}
return (bool)$result;
}
public function gc($expire_time = TIMENOW) $this->cur_query = "cache->$targetMethod($name)";
{ $this->debug('start');
$result = $this->db->query("DELETE FROM " . $this->cfg['table_name'] . " WHERE cache_expire_time < $expire_time");
return $result ? $this->db->changes() : 0;
}
public function is_installed() $result = $this->sqlite->$targetMethod($name);
{
return class_exists('SQLite3'); $this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
return $result;
} }
} }

View file

@ -1,167 +0,0 @@
<?php
/**
* TorrentPier Bull-powered BitTorrent tracker engine
*
* @copyright Copyright (c) 2005-2024 TorrentPier (https://torrentpier.com)
* @link https://github.com/torrentpier/torrentpier for the canonical source repository
* @license https://github.com/torrentpier/torrentpier/blob/master/LICENSE MIT License
*/
namespace TorrentPier\Legacy\Cache;
use SQLite3;
/**
* Class SqliteCommon
* @package TorrentPier\Legacy\Cache
*/
class SqliteCommon extends Common
{
public $cfg = [
'db_file_path' => 'sqlite.db',
'table_name' => 'table_name',
'table_schema' => 'CREATE TABLE table_name (...)',
'pconnect' => true,
'con_required' => true,
'log_name' => 'SQLite',
'shard_type' => 'none', # none, string, int (тип перевичного ключа для шардинга)
'shard_val' => 0, # для string - кол. начальных символов, для int - делитель (будет использован остаток от деления)
];
public $engine = 'SQLite';
public $dbh;
public $connected = false;
public $shard_val = false;
public $table_create_attempts = 0;
public function __construct($cfg)
{
global $debug;
$this->cfg = array_merge($this->cfg, $cfg);
$this->dbg_enabled = $debug->sqlDebugAllowed();
}
public function connect()
{
$this->cur_query = $this->dbg_enabled ? 'connect to: ' . $this->cfg['db_file_path'] : 'connect';
$this->debug('start');
if (@$this->dbh = new SQLite3($this->cfg['db_file_path'])) {
$this->connected = true;
}
if (!$this->connected && $this->cfg['con_required']) {
trigger_error('SQLite not connected', E_USER_ERROR);
}
$this->debug('stop');
$this->cur_query = null;
}
public function create_table()
{
$this->table_create_attempts++;
return $this->dbh->query($this->cfg['table_schema']);
}
public function shard($name)
{
$type = $this->cfg['shard_type'];
if ($type == 'none') {
return;
}
if (\is_array($name)) {
trigger_error('cannot shard: $name is array', E_USER_ERROR);
}
// define shard_val
if ($type == 'string') {
$shard_val = substr($name, 0, $this->cfg['shard_val']);
} else {
$shard_val = $name % $this->cfg['shard_val'];
}
// все запросы должны быть к одному и тому же шарду
if ($this->shard_val !== false) {
if ($shard_val != $this->shard_val) {
trigger_error("shard cannot be reassigned. [{$this->shard_val}, $shard_val, $name]", E_USER_ERROR);
} else {
return;
}
}
$this->shard_val = $shard_val;
$this->cfg['db_file_path'] = str_replace('*', $shard_val, $this->cfg['db_file_path']);
}
public function query($query)
{
if (!$this->connected) {
$this->connect();
}
$this->cur_query = $query;
$this->debug('start');
if (!$result = @$this->dbh->query($query)) {
$rowsresult = $this->dbh->query("PRAGMA table_info({$this->cfg['table_name']})");
$rowscount = 0;
while ($row = $rowsresult->fetchArray(SQLITE3_ASSOC)) {
$rowscount++;
}
if (!$this->table_create_attempts && !$rowscount) {
if ($this->create_table()) {
$result = $this->dbh->query($query);
}
}
if (!$result) {
$this->trigger_error($this->get_error_msg());
}
}
$this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
return $result;
}
public function fetch_row($query)
{
$result = $this->query($query);
return \is_resource($result) ? $result->fetchArray(SQLITE3_ASSOC) : false;
}
public function fetch_rowset($query)
{
$result = $this->query($query);
$rowset = [];
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
$rowset[] = $row;
}
return $rowset;
}
public function changes()
{
return \is_resource($this->dbh) ? $this->dbh->changes() : 0;
}
public function escape($str)
{
return SQLite3::escapeString($str);
}
public function get_error_msg()
{
return 'SQLite error #' . $this->dbh->lastErrorCode() . ': ' . $this->dbh->lastErrorMsg();
}
public function trigger_error($msg = 'DB Error')
{
if (error_reporting()) {
trigger_error($msg, E_USER_ERROR);
}
}
}

View file

@ -32,7 +32,6 @@ class Caches
$this->ref[$cache_name] =& $this->obj['__stub']; $this->ref[$cache_name] =& $this->obj['__stub'];
} else { } else {
$cache_type =& $engine_cfg[0]; $cache_type =& $engine_cfg[0];
$cache_cfg =& $engine_cfg[1];
switch ($cache_type) { switch ($cache_type) {
case 'apcu': case 'apcu':
@ -41,18 +40,15 @@ class Caches
} }
$this->ref[$cache_name] =& $this->obj[$cache_name]; $this->ref[$cache_name] =& $this->obj[$cache_name];
break; break;
case 'memcache': case 'memcached':
if (!isset($this->obj[$cache_name])) { if (!isset($this->obj[$cache_name])) {
$this->obj[$cache_name] = new Cache\Memcache($this->cfg['memcache'], $this->cfg['prefix']); $this->obj[$cache_name] = new Cache\Memcached($this->cfg['memcached'], $this->cfg['prefix']);
} }
$this->ref[$cache_name] =& $this->obj[$cache_name]; $this->ref[$cache_name] =& $this->obj[$cache_name];
break; break;
case 'sqlite': case 'sqlite':
if (!isset($this->obj[$cache_name])) { if (!isset($this->obj[$cache_name])) {
$cache_cfg['pconnect'] = $this->cfg['pconnect']; $this->obj[$cache_name] = new Cache\Sqlite($this->cfg['db_dir'] . $cache_name, $this->cfg['prefix']);
$cache_cfg['db_file_path'] = $this->get_db_path($cache_name, $cache_cfg, '.sqlite.db');
$this->obj[$cache_name] = new Cache\Sqlite($cache_cfg, $this->cfg['prefix']);
} }
$this->ref[$cache_name] =& $this->obj[$cache_name]; $this->ref[$cache_name] =& $this->obj[$cache_name];
break; break;
@ -75,13 +71,4 @@ class Caches
return $this->ref[$cache_name]; return $this->ref[$cache_name];
} }
public function get_db_path($name, $cfg, $ext)
{
if (!empty($cfg['shard_type']) && $cfg['shard_type'] != 'none') {
return $this->cfg['db_dir'] . $name . '_*' . $ext;
}
return $this->cfg['db_dir'] . $name . $ext;
}
} }

View file

@ -9,54 +9,99 @@
namespace TorrentPier\Legacy\Datastore; namespace TorrentPier\Legacy\Datastore;
use MatthiasMullie\Scrapbook\Adapters\Apc;
/** /**
* Class APCu * Class APCu
* @package TorrentPier\Legacy\Datastore * @package TorrentPier\Legacy\Datastore
*/ */
class APCu extends Common class APCu extends Common
{ {
public string $prefix; /**
* Cache driver name
*
* @var string
*/
public string $engine = 'APCu'; public string $engine = 'APCu';
public function __construct($prefix = null) /**
* Cache prefix
*
* @var string
*/
private string $prefix;
/**
* Adapters\Apc class
*
* @var Apc
*/
private Apc $apcu;
/**
* APCu constructor
*
* @param string $prefix
*/
public function __construct(string $prefix)
{ {
global $debug; global $debug;
if (!$this->is_installed()) { $this->apcu = new Apc();
die("Error: $this->engine extension not installed");
}
$this->prefix = $prefix; $this->prefix = $prefix;
$this->dbg_enabled = $debug->sqlDebugAllowed(); $this->dbg_enabled = $debug->sqlDebugAllowed();
} }
public function store($title, $var) /**
* Store data into cache
*
* @param string $item_name
* @param mixed $item_data
* @return bool
*/
public function store(string $item_name, mixed $item_data): bool
{ {
$this->data[$title] = $var; $this->data[$item_name] = $item_data;
$item_name = $this->prefix . $item_name;
$this->cur_query = "cache->set('$title')"; $this->cur_query = "cache->" . __FUNCTION__ . "('$item_name')";
$this->debug('start'); $this->debug('start');
$result = $this->apcu->set($item_name, $item_data);
$this->debug('stop'); $this->debug('stop');
$this->cur_query = null; $this->cur_query = null;
$this->num_queries++; $this->num_queries++;
return (bool)apcu_store($this->prefix . $title, $var); return $result;
} }
public function clean() /**
* Removes data from cache
*
* @return void
*/
public function clean(): void
{ {
foreach ($this->known_items as $title => $script_name) { foreach ($this->known_items as $title => $script_name) {
$title = $this->prefix . $title;
$this->cur_query = "cache->rm('$title')"; $this->cur_query = "cache->rm('$title')";
$this->debug('start'); $this->debug('start');
$this->apcu->delete($title);
$this->debug('stop'); $this->debug('stop');
$this->cur_query = null; $this->cur_query = null;
$this->num_queries++; $this->num_queries++;
apcu_delete($this->prefix . $title);
} }
} }
public function _fetch_from_store() /**
* Fetch cache from store
*
* @return void
*/
public function _fetch_from_store(): void
{ {
$item = null; $item = null;
if (!$items = $this->queued_items) { if (!$items = $this->queued_items) {
@ -65,18 +110,15 @@ class APCu extends Common
} }
foreach ($items as $item) { foreach ($items as $item) {
$this->cur_query = "cache->get('$item')"; $item_title = $this->prefix . $item;
$this->cur_query = "cache->get('$item_title')";
$this->debug('start'); $this->debug('start');
$this->data[$item] = $this->apcu->get($item_title);
$this->debug('stop'); $this->debug('stop');
$this->cur_query = null; $this->cur_query = null;
$this->num_queries++; $this->num_queries++;
$this->data[$item] = apcu_fetch($this->prefix . $item);
} }
} }
public function is_installed(): bool
{
return extension_loaded('apcu') && apcu_enabled();
}
} }

View file

@ -18,7 +18,7 @@ class Common
/** /**
* Директория с builder-скриптами (внутри INC_DIR) * Директория с builder-скриптами (внутри INC_DIR)
*/ */
public $ds_dir = 'datastore'; public string $ds_dir = 'datastore';
/** /**
* Готовая к употреблению data * Готовая к употреблению data
@ -86,8 +86,16 @@ class Common
return isset($this->data[$title]); return isset($this->data[$title]);
} }
public function store($item_name, $item_data) /**
* Store data into cache
*
* @param string $item_name
* @param mixed $item_data
* @return bool
*/
public function store(string $item_name, mixed $item_data): bool
{ {
return false;
} }
public function rm($items) public function rm($items)

View file

@ -9,65 +9,104 @@
namespace TorrentPier\Legacy\Datastore; namespace TorrentPier\Legacy\Datastore;
use League\Flysystem\Filesystem;
use League\Flysystem\Local\LocalFilesystemAdapter;
use MatthiasMullie\Scrapbook\Adapters\Flysystem;
/** /**
* Class File * Class File
* @package TorrentPier\Legacy\Datastore * @package TorrentPier\Legacy\Datastore
*/ */
class File extends Common class File extends Common
{ {
public $dir; /**
public $prefix; * Cache driver name
public $engine = 'Filecache'; *
* @var string
*/
public string $engine = 'File';
public function __construct($dir, $prefix = null) /**
* Cache prefix
*
* @var string
*/
private string $prefix;
/**
* Adapters\File class
*
* @var Flysystem
*/
private Flysystem $file;
/**
* File constructor
*
* @param string $dir
* @param string $prefix
*/
public function __construct(string $dir, string $prefix)
{ {
global $debug; global $debug;
$adapter = new LocalFilesystemAdapter($dir, null, LOCK_EX);
$filesystem = new Filesystem($adapter);
$this->file = new Flysystem($filesystem);
$this->prefix = $prefix; $this->prefix = $prefix;
$this->dir = $dir;
$this->dbg_enabled = $debug->sqlDebugAllowed(); $this->dbg_enabled = $debug->sqlDebugAllowed();
} }
public function store($title, $var) /**
* Store data into cache
*
* @param string $item_name
* @param mixed $item_data
* @return bool
*/
public function store(string $item_name, mixed $item_data): bool
{ {
$this->cur_query = "cache->set('$title')"; $this->data[$item_name] = $item_data;
$item_name = $this->prefix . $item_name;
$this->cur_query = "cache->" . __FUNCTION__ . "('$item_name')";
$this->debug('start'); $this->debug('start');
$this->data[$title] = $var; $result = $this->file->set($item_name, $item_data);
$filename = $this->dir . clean_filename($this->prefix . $title) . '.php';
$filecache = "<?php\n";
$filecache .= "if (!defined('BB_ROOT')) die(basename(__FILE__));\n";
$filecache .= '$filecache = ' . var_export($var, true) . ";\n";
$filecache .= '?>';
$this->debug('stop'); $this->debug('stop');
$this->cur_query = null; $this->cur_query = null;
$this->num_queries++; $this->num_queries++;
return (bool)file_write($filecache, $filename, max_size: false, replace_content: true); return $result;
} }
public function clean() /**
* Removes data from cache
*
* @return void
*/
public function clean(): void
{ {
$dir = $this->dir; foreach ($this->known_items as $title => $script_name) {
$title = $this->prefix . $title;
$this->cur_query = "cache->rm('$title')";
$this->debug('start');
if (is_dir($dir)) { $this->file->delete($title);
if ($dh = opendir($dir)) {
while (($file = readdir($dh)) !== false) {
if ($file != "." && $file != "..") {
$filename = $dir . $file;
unlink($filename); $this->debug('stop');
} $this->cur_query = null;
} $this->num_queries++;
closedir($dh);
}
} }
} }
public function _fetch_from_store() /**
* Fetch cache from store
*
* @return void
*/
public function _fetch_from_store(): void
{ {
$item = null; $item = null;
if (!$items = $this->queued_items) { if (!$items = $this->queued_items) {
@ -76,19 +115,15 @@ class File extends Common
} }
foreach ($items as $item) { foreach ($items as $item) {
$filename = $this->dir . $this->prefix . $item . '.php'; $item_title = $this->prefix . $item;
$this->cur_query = "cache->get('$item_title')";
$this->cur_query = "cache->get('$item')";
$this->debug('start'); $this->debug('start');
$this->data[$item] = $this->file->get($item_title);
$this->debug('stop'); $this->debug('stop');
$this->cur_query = null; $this->cur_query = null;
$this->num_queries++; $this->num_queries++;
if (is_file($filename) && is_readable($filename)) {
require($filename);
$this->data[$item] = $filecache;
}
} }
} }
} }

View file

@ -1,115 +0,0 @@
<?php
/**
* TorrentPier Bull-powered BitTorrent tracker engine
*
* @copyright Copyright (c) 2005-2024 TorrentPier (https://torrentpier.com)
* @link https://github.com/torrentpier/torrentpier for the canonical source repository
* @license https://github.com/torrentpier/torrentpier/blob/master/LICENSE MIT License
*/
namespace TorrentPier\Legacy\Datastore;
/**
* Class Memcache
* @package TorrentPier\Legacy\Datastore
*/
class Memcache extends Common
{
public $cfg;
public $memcache;
public $connected = false;
public $engine = 'Memcache';
public $prefix;
public function __construct($cfg, $prefix = null)
{
global $debug;
if (!$this->is_installed()) {
die("Error: $this->engine extension not installed");
}
$this->cfg = $cfg;
$this->prefix = $prefix;
$this->memcache = new \Memcache();
$this->dbg_enabled = $debug->sqlDebugAllowed();
}
public function connect()
{
$connect_type = ($this->cfg['pconnect']) ? 'pconnect' : 'connect';
$this->cur_query = $connect_type . ' ' . $this->cfg['host'] . ':' . $this->cfg['port'];
$this->debug('start');
if (@$this->memcache->$connect_type($this->cfg['host'], $this->cfg['port'])) {
$this->connected = true;
}
if (!$this->connected && $this->cfg['con_required']) {
die("Could not connect to $this->engine server");
}
$this->debug('stop');
$this->cur_query = null;
}
public function store($title, $var)
{
if (!$this->connected) {
$this->connect();
}
$this->data[$title] = $var;
$this->cur_query = "cache->set('$title')";
$this->debug('start');
$this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
return (bool)$this->memcache->set($this->prefix . $title, $var);
}
public function clean()
{
if (!$this->connected) {
$this->connect();
}
foreach ($this->known_items as $title => $script_name) {
$this->cur_query = "cache->rm('$title')";
$this->debug('start');
$this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
$this->memcache->delete($this->prefix . $title, 0);
}
}
public function _fetch_from_store()
{
$item = null;
if (!$items = $this->queued_items) {
$src = $this->_debug_find_caller('enqueue');
trigger_error("Datastore: item '$item' already enqueued [$src]", E_USER_ERROR);
}
if (!$this->connected) {
$this->connect();
}
foreach ($items as $item) {
$this->cur_query = "cache->get('$item')";
$this->debug('start');
$this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
$this->data[$item] = $this->memcache->get($this->prefix . $item);
}
}
public function is_installed()
{
return class_exists('Memcache');
}
}

View file

@ -0,0 +1,184 @@
<?php
/**
* TorrentPier Bull-powered BitTorrent tracker engine
*
* @copyright Copyright (c) 2005-2024 TorrentPier (https://torrentpier.com)
* @link https://github.com/torrentpier/torrentpier for the canonical source repository
* @license https://github.com/torrentpier/torrentpier/blob/master/LICENSE MIT License
*/
namespace TorrentPier\Legacy\Datastore;
use Memcached as MemcachedClient;
use MatthiasMullie\Scrapbook\Adapters\Memcached as MemcachedCache;
/**
* Class Memcached
* @package TorrentPier\Legacy\Datastore
*/
class Memcached extends Common
{
/**
* Cache driver name
*
* @var string
*/
public string $engine = 'Memcached';
/**
* Connection status
*
* @var bool
*/
public bool $connected = false;
/**
* Cache config
*
* @var array
*/
private array $cfg;
/**
* Cache prefix
*
* @var string
*/
private string $prefix;
/**
* Memcached class
*
* @var MemcachedClient
*/
private MemcachedClient $client;
/**
* Adapters\Memcached class
*
* @var MemcachedCache
*/
private MemcachedCache $memcached;
/**
* Memcached constructor
*
* @param array $cfg
* @param string $prefix
*/
public function __construct(array $cfg, string $prefix)
{
global $debug;
$this->client = new MemcachedClient();
$this->cfg = $cfg;
$this->prefix = $prefix;
$this->dbg_enabled = $debug->sqlDebugAllowed();
}
/**
* Connect to cache
*
* @return void
*/
private function connect(): void
{
$this->cur_query = 'connect ' . $this->cfg['host'] . ':' . $this->cfg['port'];
$this->debug('start');
if ($this->client->addServer($this->cfg['host'], $this->cfg['port'])) {
$this->connected = true;
}
if (!$this->connected) {
die("Could not connect to $this->engine server");
}
$this->memcached = new MemcachedCache($this->client);
$this->debug('stop');
$this->cur_query = null;
}
/**
* Store data into cache
*
* @param string $item_name
* @param mixed $item_data
* @return bool
*/
public function store(string $item_name, mixed $item_data): bool
{
if (!$this->connected) {
$this->connect();
}
$this->data[$item_name] = $item_data;
$item_name = $this->prefix . $item_name;
$this->cur_query = "cache->" . __FUNCTION__ . "('$item_name')";
$this->debug('start');
$result = $this->memcached->set($item_name, $item_data);
$this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
return $result;
}
/**
* Removes data from cache
*
* @return void
*/
public function clean(): void
{
if (!$this->connected) {
$this->connect();
}
foreach ($this->known_items as $title => $script_name) {
$title = $this->prefix . $title;
$this->cur_query = "cache->rm('$title')";
$this->debug('start');
$this->memcached->delete($title);
$this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
}
}
/**
* Fetch cache from store
*
* @return void
*/
public function _fetch_from_store(): void
{
$item = null;
if (!$items = $this->queued_items) {
$src = $this->_debug_find_caller('enqueue');
trigger_error("Datastore: item '$item' already enqueued [$src]", E_USER_ERROR);
}
if (!$this->connected) {
$this->connect();
}
foreach ($items as $item) {
$item_title = $this->prefix . $item;
$this->cur_query = "cache->get('$item_title')";
$this->debug('start');
$this->data[$item] = $this->memcached->get($item_title);
$this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
}
}
}

View file

@ -9,84 +9,157 @@
namespace TorrentPier\Legacy\Datastore; namespace TorrentPier\Legacy\Datastore;
use Redis as RedisClient;
use MatthiasMullie\Scrapbook\Adapters\Redis as RedisCache;
/** /**
* Class Redis * Class Redis
* @package TorrentPier\Legacy\Datastore * @package TorrentPier\Legacy\Datastore
*/ */
class Redis extends Common class Redis extends Common
{ {
public $cfg; /**
public $redis; * Cache driver name
public $prefix; *
public $connected = false; * @var string
public $engine = 'Redis'; */
public string $engine = 'Redis';
public function __construct($cfg, $prefix = null) /**
* Connection status
*
* @var bool
*/
public bool $connected = false;
/**
* Cache config
*
* @var array
*/
private array $cfg;
/**
* Cache prefix
*
* @var string
*/
private string $prefix;
/**
* Redis class
*
* @var RedisClient
*/
private RedisClient $client;
/**
* Adapters\Redis class
*
* @var RedisCache
*/
private RedisCache $redis;
/**
* Redis constructor
*
* @param array $cfg
* @param string $prefix
*/
public function __construct(array $cfg, string $prefix)
{ {
global $debug; global $debug;
if (!$this->is_installed()) { $this->client = new RedisClient();
die("Error: $this->engine extension not installed");
}
$this->cfg = $cfg; $this->cfg = $cfg;
$this->redis = new \Redis();
$this->dbg_enabled = $debug->sqlDebugAllowed();
$this->prefix = $prefix; $this->prefix = $prefix;
$this->dbg_enabled = $debug->sqlDebugAllowed();
} }
public function connect() /**
* Connect to cache
*
* @return void
*/
private function connect(): void
{ {
$connect_type = ($this->cfg['pconnect']) ? 'pconnect' : 'connect'; $connectType = $this->cfg['pconnect'] ? 'pconnect' : 'connect';
$this->cur_query = $connect_type . ' ' . $this->cfg['host'] . ':' . $this->cfg['port']; $this->cur_query = $connectType . ' ' . $this->cfg['host'] . ':' . $this->cfg['port'];
$this->debug('start'); $this->debug('start');
if (@$this->redis->$connect_type($this->cfg['host'], $this->cfg['port'])) { if ($this->client->$connectType($this->cfg['host'], $this->cfg['port'])) {
$this->connected = true; $this->connected = true;
} }
if (!$this->connected && $this->cfg['con_required']) { if (!$this->connected) {
die("Could not connect to $this->engine server"); die("Could not connect to $this->engine server");
} }
$this->redis = new RedisCache($this->client);
$this->debug('stop'); $this->debug('stop');
$this->cur_query = null; $this->cur_query = null;
} }
public function store($title, $var) /**
* Store data into cache
*
* @param string $item_name
* @param mixed $item_data
* @return bool
*/
public function store(string $item_name, mixed $item_data): bool
{ {
if (!$this->connected) { if (!$this->connected) {
$this->connect(); $this->connect();
} }
$this->data[$title] = $var;
$this->cur_query = "cache->set('$title')"; $this->data[$item_name] = $item_data;
$item_name = $this->prefix . $item_name;
$this->cur_query = "cache->" . __FUNCTION__ . "('$item_name')";
$this->debug('start'); $this->debug('start');
$result = $this->redis->set($item_name, $item_data);
$this->debug('stop'); $this->debug('stop');
$this->cur_query = null; $this->cur_query = null;
$this->num_queries++; $this->num_queries++;
return (bool)$this->redis->set($this->prefix . $title, serialize($var)); return $result;
} }
public function clean() /**
* Removes data from cache
*
* @return void
*/
public function clean(): void
{ {
if (!$this->connected) { if (!$this->connected) {
$this->connect(); $this->connect();
} }
foreach ($this->known_items as $title => $script_name) { foreach ($this->known_items as $title => $script_name) {
$title = $this->prefix . $title;
$this->cur_query = "cache->rm('$title')"; $this->cur_query = "cache->rm('$title')";
$this->debug('start'); $this->debug('start');
$this->redis->delete($title);
$this->debug('stop'); $this->debug('stop');
$this->cur_query = null; $this->cur_query = null;
$this->num_queries++; $this->num_queries++;
$this->redis->del($this->prefix . $title);
} }
} }
public function _fetch_from_store() /**
* Fetch cache from store
*
* @return void
*/
public function _fetch_from_store(): void
{ {
$item = null; $item = null;
if (!$items = $this->queued_items) { if (!$items = $this->queued_items) {
@ -97,19 +170,17 @@ class Redis extends Common
if (!$this->connected) { if (!$this->connected) {
$this->connect(); $this->connect();
} }
foreach ($items as $item) { foreach ($items as $item) {
$this->cur_query = "cache->get('$item')"; $item_title = $this->prefix . $item;
$this->cur_query = "cache->get('$item_title')";
$this->debug('start'); $this->debug('start');
$this->data[$item] = $this->redis->get($item_title);
$this->debug('stop'); $this->debug('stop');
$this->cur_query = null; $this->cur_query = null;
$this->num_queries++; $this->num_queries++;
$this->data[$item] = unserialize($this->redis->get($this->prefix . $item));
} }
} }
public function is_installed()
{
return class_exists('Redis');
}
} }

View file

@ -9,7 +9,8 @@
namespace TorrentPier\Legacy\Datastore; namespace TorrentPier\Legacy\Datastore;
use SQLite3; use MatthiasMullie\Scrapbook\Adapters\SQLite as SQLiteCache;
use PDO;
/** /**
* Class Sqlite * Class Sqlite
@ -17,73 +18,110 @@ use SQLite3;
*/ */
class Sqlite extends Common class Sqlite extends Common
{ {
public $engine = 'SQLite'; /**
public $db; * Cache driver name
public $prefix; *
public $cfg = [ * @var string
'db_file_path' => '/path/to/datastore.db.sqlite', */
'table_name' => 'datastore', public string $engine = 'SQLite';
'table_schema' => 'CREATE TABLE datastore (
ds_title VARCHAR(255),
ds_data TEXT,
PRIMARY KEY (ds_title)
)',
'pconnect' => true,
'con_required' => true,
'log_name' => 'DATASTORE',
];
public function __construct($cfg, $prefix = null) /**
* Cache prefix
*
* @var string
*/
private string $prefix;
/**
* Adapters\SQLite class
*
* @var SQLiteCache
*/
private SQLiteCache $sqlite;
/**
* Sqlite constructor
*
* @param string $dir
* @param string $prefix
*/
public function __construct(string $dir, string $prefix)
{ {
if (!$this->is_installed()) { global $debug;
die('Error: SQLite3 extension not installed');
}
$this->cfg = array_merge($this->cfg, $cfg); $client = new PDO("sqlite:$dir.db");
$this->db = new SqliteCommon($this->cfg); $this->sqlite = new SQLiteCache($client);
$this->prefix = $prefix; $this->prefix = $prefix;
$this->dbg_enabled = $debug->sqlDebugAllowed();
} }
public function store($item_name, $item_data) /**
* Store data into cache
*
* @param string $item_name
* @param mixed $item_data
* @return bool
*/
public function store(string $item_name, mixed $item_data): bool
{ {
$this->data[$item_name] = $item_data; $this->data[$item_name] = $item_data;
$item_name = $this->prefix . $item_name;
$ds_title = SQLite3::escapeString($this->prefix . $item_name); $this->cur_query = "cache->" . __FUNCTION__ . "('$item_name')";
$ds_data = SQLite3::escapeString(serialize($item_data)); $this->debug('start');
$result = $this->db->query("REPLACE INTO " . $this->cfg['table_name'] . " (ds_title, ds_data) VALUES ('$ds_title', '$ds_data')"); $result = $this->sqlite->set($item_name, $item_data);
return (bool)$result; $this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
return $result;
} }
public function clean() /**
* Removes data from cache
*
* @return void
*/
public function clean(): void
{ {
$this->db->query("DELETE FROM " . $this->cfg['table_name']); foreach ($this->known_items as $title => $script_name) {
$title = $this->prefix . $title;
$this->cur_query = "cache->rm('$title')";
$this->debug('start');
$this->sqlite->delete($title);
$this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
}
} }
public function _fetch_from_store() /**
* Fetch cache from store
*
* @return void
*/
public function _fetch_from_store(): void
{ {
$item = null;
if (!$items = $this->queued_items) { if (!$items = $this->queued_items) {
return; $src = $this->_debug_find_caller('enqueue');
trigger_error("Datastore: item '$item' already enqueued [$src]", E_USER_ERROR);
} }
$prefix_len = \strlen($this->prefix); foreach ($items as $item) {
$prefix_sql = SQLite3::escapeString($this->prefix); $item_title = $this->prefix . $item;
$this->cur_query = "cache->get('$item_title')";
$this->debug('start');
array_deep($items, 'SQLite3::escapeString'); $this->data[$item] = $this->sqlite->get($item_title);
$items_list = $prefix_sql . implode("','$prefix_sql", $items);
$rowset = $this->db->fetch_rowset("SELECT ds_title, ds_data FROM " . $this->cfg['table_name'] . " WHERE ds_title IN ('$items_list')"); $this->debug('stop');
$this->cur_query = null;
$this->db->debug('start', "unserialize()"); $this->num_queries++;
foreach ($rowset as $row) { }
$this->data[substr($row['ds_title'], $prefix_len)] = unserialize($row['ds_data']);
}
$this->db->debug('stop');
}
public function is_installed()
{
return class_exists('SQLite3');
} }
} }

View file

@ -1,167 +0,0 @@
<?php
/**
* TorrentPier Bull-powered BitTorrent tracker engine
*
* @copyright Copyright (c) 2005-2024 TorrentPier (https://torrentpier.com)
* @link https://github.com/torrentpier/torrentpier for the canonical source repository
* @license https://github.com/torrentpier/torrentpier/blob/master/LICENSE MIT License
*/
namespace TorrentPier\Legacy\Datastore;
use SQLite3;
/**
* Class SqliteCommon
* @package TorrentPier\Legacy\Datastore
*/
class SqliteCommon extends Common
{
public $cfg = [
'db_file_path' => 'sqlite.db',
'table_name' => 'table_name',
'table_schema' => 'CREATE TABLE table_name (...)',
'pconnect' => true,
'con_required' => true,
'log_name' => 'SQLite',
'shard_type' => 'none', # none, string, int (тип перевичного ключа для шардинга)
'shard_val' => 0, # для string - кол. начальных символов, для int - делитель (будет использован остаток от деления)
];
public $engine = 'SQLite';
public $dbh;
public $connected = false;
public $shard_val = false;
public $table_create_attempts = 0;
public function __construct($cfg)
{
global $debug;
$this->cfg = array_merge($this->cfg, $cfg);
$this->dbg_enabled = $debug->sqlDebugAllowed();
}
public function connect()
{
$this->cur_query = $this->dbg_enabled ? 'connect to: ' . $this->cfg['db_file_path'] : 'connect';
$this->debug('start');
if (@$this->dbh = new SQLite3($this->cfg['db_file_path'])) {
$this->connected = true;
}
if (!$this->connected && $this->cfg['con_required']) {
trigger_error('SQLite not connected', E_USER_ERROR);
}
$this->debug('stop');
$this->cur_query = null;
}
public function create_table()
{
$this->table_create_attempts++;
return $this->dbh->query($this->cfg['table_schema']);
}
public function shard($name)
{
$type = $this->cfg['shard_type'];
if ($type == 'none') {
return;
}
if (\is_array($name)) {
trigger_error('cannot shard: $name is array', E_USER_ERROR);
}
// define shard_val
if ($type == 'string') {
$shard_val = substr($name, 0, $this->cfg['shard_val']);
} else {
$shard_val = $name % $this->cfg['shard_val'];
}
// все запросы должны быть к одному и тому же шарду
if ($this->shard_val !== false) {
if ($shard_val != $this->shard_val) {
trigger_error("shard cannot be reassigned. [{$this->shard_val}, $shard_val, $name]", E_USER_ERROR);
} else {
return;
}
}
$this->shard_val = $shard_val;
$this->cfg['db_file_path'] = str_replace('*', $shard_val, $this->cfg['db_file_path']);
}
public function query($query)
{
if (!$this->connected) {
$this->connect();
}
$this->cur_query = $query;
$this->debug('start');
if (!$result = @$this->dbh->query($query)) {
$rowsresult = $this->dbh->query("PRAGMA table_info({$this->cfg['table_name']})");
$rowscount = 0;
while ($row = $rowsresult->fetchArray(SQLITE3_ASSOC)) {
$rowscount++;
}
if (!$this->table_create_attempts && !$rowscount) {
if ($this->create_table()) {
$result = $this->dbh->query($query);
}
}
if (!$result) {
$this->trigger_error($this->get_error_msg());
}
}
$this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
return $result;
}
public function fetch_row($query)
{
$result = $this->query($query);
return \is_resource($result) ? $result->fetchArray(SQLITE3_ASSOC) : false;
}
public function fetch_rowset($query)
{
$result = $this->query($query);
$rowset = [];
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
$rowset[] = $row;
}
return $rowset;
}
public function changes()
{
return \is_resource($this->dbh) ? $this->dbh->changes() : 0;
}
public function escape($str)
{
return SQLite3::escapeString($str);
}
public function get_error_msg()
{
return 'SQLite error #' . $this->dbh->lastErrorCode() . ': ' . $this->dbh->lastErrorMsg();
}
public function trigger_error($msg = 'DB Error')
{
if (error_reporting()) {
trigger_error($msg, E_USER_ERROR);
}
}
}