mirror of
https://github.com/NNTmux/newznab-tmux.git
synced 2026-08-28 17:01:16 +00:00
Update elasticsearch-php package to version 8
This commit is contained in:
@@ -4,9 +4,11 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Elasticsearch\ClientBuilder;
|
||||
use App\Services\Search\Support\ElasticsearchClientFactory;
|
||||
use App\Services\Search\Support\ElasticsearchResponseHelper;
|
||||
use Elastic\Elasticsearch\Client as ElasticsearchClient;
|
||||
use Illuminate\Console\Command;
|
||||
use Manticoresearch\Client;
|
||||
use Manticoresearch\Client as ManticoreClient;
|
||||
use Manticoresearch\Exceptions\ResponseException;
|
||||
|
||||
class CreateMediaIndexes extends Command
|
||||
@@ -54,7 +56,7 @@ class CreateMediaIndexes extends Command
|
||||
$host = config('search.drivers.manticore.host', '127.0.0.1');
|
||||
$port = config('search.drivers.manticore.port', 9308);
|
||||
|
||||
$client = new Client([
|
||||
$client = new ManticoreClient([
|
||||
'host' => $host,
|
||||
'port' => $port,
|
||||
]);
|
||||
@@ -147,7 +149,7 @@ class CreateMediaIndexes extends Command
|
||||
*
|
||||
* @param array<string, mixed> $schema
|
||||
*/
|
||||
private function createManticoreIndex(Client $client, string $indexName, array $schema, bool $dropExisting): bool
|
||||
private function createManticoreIndex(ManticoreClient $client, string $indexName, array $schema, bool $dropExisting): bool
|
||||
{
|
||||
try {
|
||||
// Check if index exists
|
||||
@@ -266,20 +268,22 @@ class CreateMediaIndexes extends Command
|
||||
];
|
||||
|
||||
try {
|
||||
// Create Elasticsearch client directly
|
||||
$esConfig = config('search.drivers.elasticsearch');
|
||||
$esClient = ClientBuilder::create()
|
||||
->setHosts($esConfig['hosts'] ?? [['host' => 'localhost', 'port' => 9200]])
|
||||
->build();
|
||||
/** @var ElasticsearchClient $esClient */
|
||||
$esClient = ElasticsearchClientFactory::make($esConfig ?? []);
|
||||
|
||||
// Create movies index
|
||||
$moviesIndex = config('search.drivers.elasticsearch.indexes.movies', 'movies');
|
||||
if ($dropExisting && $esClient->indices()->exists(['index' => $moviesIndex])) {
|
||||
if ($dropExisting && (ElasticsearchResponseHelper::boolResponse($esClient, function (ElasticsearchClient $client) use ($moviesIndex) {
|
||||
return $client->indices()->exists(['index' => $moviesIndex]);
|
||||
}))) {
|
||||
$this->warn("Dropping existing index: {$moviesIndex}");
|
||||
$esClient->indices()->delete(['index' => $moviesIndex]);
|
||||
}
|
||||
|
||||
if (! $esClient->indices()->exists(['index' => $moviesIndex])) {
|
||||
if (! (ElasticsearchResponseHelper::boolResponse($esClient, function (ElasticsearchClient $client) use ($moviesIndex) {
|
||||
return $client->indices()->exists(['index' => $moviesIndex]);
|
||||
}))) {
|
||||
$this->info("Creating index: {$moviesIndex}");
|
||||
$esClient->indices()->create([
|
||||
'index' => $moviesIndex,
|
||||
@@ -292,12 +296,16 @@ class CreateMediaIndexes extends Command
|
||||
|
||||
// Create tvshows index
|
||||
$tvshowsIndex = config('search.drivers.elasticsearch.indexes.tvshows', 'tvshows');
|
||||
if ($dropExisting && $esClient->indices()->exists(['index' => $tvshowsIndex])) {
|
||||
if ($dropExisting && (ElasticsearchResponseHelper::boolResponse($esClient, function (ElasticsearchClient $client) use ($tvshowsIndex) {
|
||||
return $client->indices()->exists(['index' => $tvshowsIndex]);
|
||||
}))) {
|
||||
$this->warn("Dropping existing index: {$tvshowsIndex}");
|
||||
$esClient->indices()->delete(['index' => $tvshowsIndex]);
|
||||
}
|
||||
|
||||
if (! $esClient->indices()->exists(['index' => $tvshowsIndex])) {
|
||||
if (! (ElasticsearchResponseHelper::boolResponse($esClient, function (ElasticsearchClient $client) use ($tvshowsIndex) {
|
||||
return $client->indices()->exists(['index' => $tvshowsIndex]);
|
||||
}))) {
|
||||
$this->info("Creating index: {$tvshowsIndex}");
|
||||
$esClient->indices()->create([
|
||||
'index' => $tvshowsIndex,
|
||||
|
||||
@@ -5,6 +5,8 @@ declare(strict_types=1);
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Facades\Elasticsearch;
|
||||
use App\Services\Search\Support\ElasticsearchResponseHelper;
|
||||
use Elastic\Elasticsearch\Client as ElasticsearchClient;
|
||||
use Exception;
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
@@ -68,7 +70,9 @@ class NntmuxCheckIndex extends Command
|
||||
{
|
||||
try {
|
||||
// Check if index exists
|
||||
$exists = Elasticsearch::indices()->exists(['index' => $index]);
|
||||
/** @var ElasticsearchClient $client */
|
||||
$client = app('elasticsearch');
|
||||
$exists = ElasticsearchResponseHelper::boolResponse($client, fn (ElasticsearchClient $elasticClient) => $elasticClient->indices()->exists(['index' => $index]));
|
||||
|
||||
if (! $exists) {
|
||||
$this->error("ElasticSearch index '{$index}' does not exist.");
|
||||
|
||||
@@ -5,6 +5,8 @@ declare(strict_types=1);
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Facades\Elasticsearch;
|
||||
use App\Services\Search\Support\ElasticsearchResponseHelper;
|
||||
use Elastic\Elasticsearch\Client;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class NntmuxCreateESIndexes extends Command
|
||||
@@ -28,7 +30,10 @@ class NntmuxCreateESIndexes extends Command
|
||||
*/
|
||||
public function handle(): void
|
||||
{
|
||||
if (Elasticsearch::indices()->exists(['index' => 'releases'])) {
|
||||
/** @var Client $client */
|
||||
$client = app('elasticsearch');
|
||||
|
||||
if (ElasticsearchResponseHelper::boolResponse($client, fn (Client $elasticClient) => $elasticClient->indices()->exists(['index' => 'releases']))) {
|
||||
Elasticsearch::indices()->delete(['index' => 'releases']);
|
||||
}
|
||||
$releases_index = [
|
||||
@@ -110,7 +115,7 @@ class NntmuxCreateESIndexes extends Command
|
||||
$response = Elasticsearch::indices()->create($releases_index);
|
||||
|
||||
$this->info('Index releases created successfully');
|
||||
if (Elasticsearch::indices()->exists(['index' => 'predb'])) {
|
||||
if (ElasticsearchResponseHelper::boolResponse($client, fn (Client $elasticClient) => $elasticClient->indices()->exists(['index' => 'predb']))) {
|
||||
Elasticsearch::indices()->delete(['index' => 'predb']);
|
||||
}
|
||||
$predb_index = [
|
||||
|
||||
@@ -8,6 +8,8 @@ use App\Facades\Elasticsearch;
|
||||
use App\Facades\Search;
|
||||
use App\Models\Predb;
|
||||
use App\Models\Release;
|
||||
use App\Services\Search\Support\ElasticsearchResponseHelper;
|
||||
use Elastic\Elasticsearch\Client as ElasticsearchClient;
|
||||
use Exception;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Process;
|
||||
@@ -290,7 +292,9 @@ class NntmuxOffsetPopulate extends Command
|
||||
} else {
|
||||
// For ElasticSearch, just clear the data instead of recreating the index
|
||||
try {
|
||||
$exists = Elasticsearch::indices()->exists(['index' => $index]);
|
||||
/** @var ElasticsearchClient $client */
|
||||
$client = app('elasticsearch');
|
||||
$exists = ElasticsearchResponseHelper::boolResponse($client, fn (ElasticsearchClient $elasticClient) => $elasticClient->indices()->exists(['index' => $index]));
|
||||
|
||||
if ($exists) {
|
||||
// Get current document count
|
||||
|
||||
@@ -7,6 +7,8 @@ namespace App\Console\Commands;
|
||||
use App\Facades\Elasticsearch;
|
||||
use App\Facades\Search;
|
||||
use App\Models\UsenetGroup;
|
||||
use App\Services\Search\Support\ElasticsearchResponseHelper;
|
||||
use Elastic\Elasticsearch\Client as ElasticsearchClient;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\File;
|
||||
@@ -94,7 +96,10 @@ class NntmuxResetDb extends Command
|
||||
unset($value);
|
||||
|
||||
if (config('search.default') === 'elasticsearch') {
|
||||
if (Elasticsearch::indices()->exists(['index' => 'releases'])) {
|
||||
/** @var ElasticsearchClient $client */
|
||||
$client = app('elasticsearch');
|
||||
|
||||
if (ElasticsearchResponseHelper::boolResponse($client, fn (ElasticsearchClient $elasticClient) => $elasticClient->indices()->exists(['index' => 'releases']))) {
|
||||
Elasticsearch::indices()->delete(['index' => 'releases']);
|
||||
}
|
||||
$releases_index = [
|
||||
@@ -138,7 +143,7 @@ class NntmuxResetDb extends Command
|
||||
|
||||
Elasticsearch::indices()->create($releases_index);
|
||||
|
||||
if (Elasticsearch::indices()->exists(['index' => 'predb'])) {
|
||||
if (ElasticsearchResponseHelper::boolResponse($client, fn (ElasticsearchClient $elasticClient) => $elasticClient->indices()->exists(['index' => 'predb']))) {
|
||||
Elasticsearch::indices()->delete(['index' => 'predb']);
|
||||
}
|
||||
$predb_index = [
|
||||
@@ -173,7 +178,7 @@ class NntmuxResetDb extends Command
|
||||
Elasticsearch::indices()->create($predb_index);
|
||||
|
||||
// Delete and recreate movies index
|
||||
if (Elasticsearch::indices()->exists(['index' => 'movies'])) {
|
||||
if (ElasticsearchResponseHelper::boolResponse($client, fn (ElasticsearchClient $elasticClient) => $elasticClient->indices()->exists(['index' => 'movies']))) {
|
||||
Elasticsearch::indices()->delete(['index' => 'movies']);
|
||||
}
|
||||
$movies_index = [
|
||||
@@ -214,7 +219,7 @@ class NntmuxResetDb extends Command
|
||||
Elasticsearch::indices()->create($movies_index);
|
||||
|
||||
// Delete and recreate tvshows index
|
||||
if (Elasticsearch::indices()->exists(['index' => 'tvshows'])) {
|
||||
if (ElasticsearchResponseHelper::boolResponse($client, fn (ElasticsearchClient $elasticClient) => $elasticClient->indices()->exists(['index' => 'tvshows']))) {
|
||||
Elasticsearch::indices()->delete(['index' => 'tvshows']);
|
||||
}
|
||||
$tvshows_index = [
|
||||
|
||||
@@ -6,6 +6,8 @@ namespace App\Console\Commands;
|
||||
|
||||
use App\Facades\Elasticsearch;
|
||||
use App\Models\Release;
|
||||
use App\Services\Search\Support\ElasticsearchResponseHelper;
|
||||
use Elastic\Elasticsearch\Client as ElasticsearchClient;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
@@ -50,6 +52,8 @@ class UpdateReleasesIndexSchemaES extends Command
|
||||
'movieinfo_id' => ['type' => 'integer'],
|
||||
];
|
||||
|
||||
private ?ElasticsearchClient $client = null;
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*/
|
||||
@@ -108,6 +112,19 @@ class UpdateReleasesIndexSchemaES extends Command
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function elasticsearchClient(): ElasticsearchClient
|
||||
{
|
||||
if ($this->client instanceof ElasticsearchClient) {
|
||||
return $this->client;
|
||||
}
|
||||
|
||||
/** @var ElasticsearchClient $client */
|
||||
$client = app('elasticsearch');
|
||||
$this->client = $client;
|
||||
|
||||
return $this->client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show current index schema information
|
||||
*/
|
||||
@@ -119,7 +136,7 @@ class UpdateReleasesIndexSchemaES extends Command
|
||||
try {
|
||||
$indexName = config('search.drivers.elasticsearch.indexes.releases', 'releases');
|
||||
|
||||
if (! Elasticsearch::indices()->exists(['index' => $indexName])) {
|
||||
if (! ElasticsearchResponseHelper::boolResponse($this->elasticsearchClient(), fn (ElasticsearchClient $client) => $client->indices()->exists(['index' => $indexName]))) {
|
||||
$this->warn("Index '{$indexName}' does not exist.");
|
||||
$this->info('Run `php artisan nntmux:create-es-indexes` to create the index first.');
|
||||
|
||||
@@ -206,7 +223,7 @@ class UpdateReleasesIndexSchemaES extends Command
|
||||
try {
|
||||
$indexName = config('search.drivers.elasticsearch.indexes.releases', 'releases');
|
||||
|
||||
if (! Elasticsearch::indices()->exists(['index' => $indexName])) {
|
||||
if (! ElasticsearchResponseHelper::boolResponse($this->elasticsearchClient(), fn (ElasticsearchClient $client) => $client->indices()->exists(['index' => $indexName]))) {
|
||||
$this->error("Index '{$indexName}' does not exist. Create it first with: php artisan nntmux:create-es-indexes");
|
||||
|
||||
return Command::FAILURE;
|
||||
@@ -287,7 +304,7 @@ class UpdateReleasesIndexSchemaES extends Command
|
||||
|
||||
try {
|
||||
// Delete existing index if it exists
|
||||
if (Elasticsearch::indices()->exists(['index' => $indexName])) {
|
||||
if (ElasticsearchResponseHelper::boolResponse($this->elasticsearchClient(), fn (ElasticsearchClient $client) => $client->indices()->exists(['index' => $indexName]))) {
|
||||
$this->info("Deleting existing '{$indexName}' index...");
|
||||
Elasticsearch::indices()->delete(['index' => $indexName]);
|
||||
}
|
||||
@@ -411,7 +428,7 @@ class UpdateReleasesIndexSchemaES extends Command
|
||||
$indexName = config('search.drivers.elasticsearch.indexes.releases', 'releases');
|
||||
|
||||
// Check if index exists
|
||||
if (! Elasticsearch::indices()->exists(['index' => $indexName])) {
|
||||
if (! ElasticsearchResponseHelper::boolResponse($this->elasticsearchClient(), fn (ElasticsearchClient $client) => $client->indices()->exists(['index' => $indexName]))) {
|
||||
$this->error("Index '{$indexName}' does not exist. Create it first.");
|
||||
|
||||
return Command::FAILURE;
|
||||
|
||||
@@ -4,18 +4,18 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Facades;
|
||||
|
||||
use Elasticsearch\Client;
|
||||
use Elastic\Elasticsearch\Client;
|
||||
use Illuminate\Support\Facades\Facade;
|
||||
|
||||
/**
|
||||
* Elasticsearch Facade - provides static access to Elasticsearch client.
|
||||
*
|
||||
* @method static \Elasticsearch\Namespaces\IndicesNamespace indices()
|
||||
* @method static \Elasticsearch\Namespaces\ClusterNamespace cluster()
|
||||
* @method static array search(array $params)
|
||||
* @method static array bulk(array $params)
|
||||
* @method static array get(array $params)
|
||||
* @method static array deleteByQuery(array $params)
|
||||
* @method static \Elastic\Elasticsearch\Endpoints\Indices indices()
|
||||
* @method static \Elastic\Elasticsearch\Endpoints\Cluster cluster()
|
||||
* @method static \Elastic\Elasticsearch\Response\Elasticsearch search(array $params)
|
||||
* @method static \Elastic\Elasticsearch\Response\Elasticsearch bulk(array $params)
|
||||
* @method static \Elastic\Elasticsearch\Response\Elasticsearch get(array $params)
|
||||
* @method static \Elastic\Elasticsearch\Response\Elasticsearch deleteByQuery(array $params)
|
||||
*
|
||||
* @see Client
|
||||
*/
|
||||
|
||||
@@ -10,8 +10,8 @@ use App\Services\Search\Drivers\ElasticSearchDriver;
|
||||
use App\Services\Search\Drivers\ManticoreSearchDriver;
|
||||
use App\Services\Search\MediaSearchService;
|
||||
use App\Services\Search\SearchService;
|
||||
use Elasticsearch\Client;
|
||||
use Elasticsearch\ClientBuilder;
|
||||
use App\Services\Search\Support\ElasticsearchClientFactory;
|
||||
use Elastic\Elasticsearch\Client;
|
||||
use Illuminate\Contracts\Foundation\Application;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
|
||||
@@ -63,11 +63,8 @@ class SearchServiceProvider extends ServiceProvider
|
||||
|
||||
$this->app->singleton('elasticsearch', function (): Client {
|
||||
$config = config('search.drivers.elasticsearch', []);
|
||||
$clientBuilder = ClientBuilder::create();
|
||||
$clientBuilder->setHosts($config['hosts'] ?? []);
|
||||
$clientBuilder->setRetries($config['retries'] ?? 2);
|
||||
|
||||
return $clientBuilder->build();
|
||||
return ElasticsearchClientFactory::make($config);
|
||||
});
|
||||
|
||||
// Register aliases (using prefixed names to avoid conflicts with other packages)
|
||||
|
||||
@@ -8,11 +8,10 @@ use App\Models\MovieInfo;
|
||||
use App\Models\Release;
|
||||
use App\Models\Video;
|
||||
use App\Services\Search\Contracts\SearchDriverInterface;
|
||||
use Elasticsearch\Client;
|
||||
use Elasticsearch\ClientBuilder;
|
||||
use Elasticsearch\Common\Exceptions\ElasticsearchException;
|
||||
use Elasticsearch\Common\Exceptions\Missing404Exception;
|
||||
use GuzzleHttp\Ring\Client\CurlHandler;
|
||||
use App\Services\Search\Support\ElasticsearchClientFactory;
|
||||
use App\Services\Search\Support\ElasticsearchResponseHelper;
|
||||
use Elastic\Elasticsearch\Client;
|
||||
use Elastic\Elasticsearch\Exception\ElasticsearchException;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
@@ -91,38 +90,17 @@ class ElasticSearchDriver implements SearchDriverInterface
|
||||
{
|
||||
if (self::$client === null) {
|
||||
try {
|
||||
if (! extension_loaded('curl')) {
|
||||
throw new RuntimeException('cURL extension is not loaded');
|
||||
}
|
||||
|
||||
if (empty($this->config)) {
|
||||
throw new RuntimeException('Elasticsearch configuration not found');
|
||||
}
|
||||
|
||||
$clientBuilder = ClientBuilder::create();
|
||||
$hosts = $this->buildHostsArray($this->config['hosts'] ?? []);
|
||||
|
||||
if (empty($hosts)) {
|
||||
throw new RuntimeException('No Elasticsearch hosts configured');
|
||||
}
|
||||
|
||||
if (config('app.debug')) {
|
||||
Log::debug('Elasticsearch client initializing', [
|
||||
'hosts' => $hosts,
|
||||
'hosts' => ElasticsearchClientFactory::buildHosts($this->config['hosts'] ?? []),
|
||||
]);
|
||||
}
|
||||
|
||||
$clientBuilder->setHosts($hosts);
|
||||
$clientBuilder->setHandler(new CurlHandler);
|
||||
$clientBuilder->setConnectionParams([
|
||||
'timeout' => $this->config['timeout'] ?? self::DEFAULT_TIMEOUT,
|
||||
'connect_timeout' => $this->config['connect_timeout'] ?? self::DEFAULT_CONNECT_TIMEOUT,
|
||||
]);
|
||||
|
||||
// Enable retries for better resilience
|
||||
$clientBuilder->setRetries($this->config['retries'] ?? 2);
|
||||
|
||||
self::$client = $clientBuilder->build();
|
||||
self::$client = ElasticsearchClientFactory::make($this->config);
|
||||
|
||||
if (config('app.debug')) {
|
||||
Log::debug('Elasticsearch client initialized successfully');
|
||||
@@ -139,43 +117,10 @@ class ElasticSearchDriver implements SearchDriverInterface
|
||||
return self::$client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build hosts array from configuration.
|
||||
*
|
||||
* @param array<string, mixed> $configHosts Configuration hosts array
|
||||
* @return array<string, mixed> Formatted hosts array for Elasticsearch client
|
||||
*/
|
||||
private function buildHostsArray(array $configHosts): array
|
||||
{
|
||||
$hosts = [];
|
||||
|
||||
foreach ($configHosts as $host) {
|
||||
$hostConfig = [
|
||||
'host' => $host['host'] ?? 'localhost',
|
||||
'port' => $host['port'] ?? 9200,
|
||||
];
|
||||
|
||||
if (! empty($host['scheme'])) {
|
||||
$hostConfig['scheme'] = $host['scheme'];
|
||||
}
|
||||
|
||||
if (! empty($host['user']) && ! empty($host['pass'])) {
|
||||
$hostConfig['user'] = $host['user'];
|
||||
$hostConfig['pass'] = $host['pass'];
|
||||
}
|
||||
|
||||
$hosts[] = $hostConfig;
|
||||
}
|
||||
|
||||
return $hosts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if Elasticsearch is available.
|
||||
*
|
||||
* Caches the availability status to avoid frequent ping requests.
|
||||
*
|
||||
* @return list<array<string, mixed>>
|
||||
*/
|
||||
private function isElasticsearchAvailable(): bool
|
||||
{
|
||||
@@ -190,7 +135,7 @@ class ElasticSearchDriver implements SearchDriverInterface
|
||||
|
||||
try {
|
||||
$client = $this->getClient();
|
||||
$result = $client->ping();
|
||||
$result = ElasticsearchResponseHelper::boolResponse($client, fn (Client $elasticClient) => $elasticClient->ping());
|
||||
|
||||
if (config('app.debug')) {
|
||||
Log::debug('Elasticsearch ping result', ['available' => $result]);
|
||||
@@ -1268,16 +1213,23 @@ class ElasticSearchDriver implements SearchDriverInterface
|
||||
'id' => $id,
|
||||
]);
|
||||
|
||||
} catch (Missing404Exception $e) {
|
||||
// Document already deleted, not an error
|
||||
if (config('app.debug')) {
|
||||
Log::debug('ElasticSearch deleteRelease: document not found', ['release_id' => $id]);
|
||||
}
|
||||
} catch (ElasticsearchException $e) {
|
||||
Log::error('ElasticSearch deleteRelease error: '.$e->getMessage(), [
|
||||
'release_id' => $id,
|
||||
]);
|
||||
} catch (\Throwable $e) {
|
||||
if (ElasticsearchResponseHelper::isNotFound($e)) {
|
||||
if (config('app.debug')) {
|
||||
Log::debug('ElasticSearch deleteRelease: document not found', ['release_id' => $id]);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($e instanceof ElasticsearchException) {
|
||||
Log::error('ElasticSearch deleteRelease error: '.$e->getMessage(), [
|
||||
'release_id' => $id,
|
||||
]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Log::error('ElasticSearch deleteRelease unexpected error: '.$e->getMessage(), [
|
||||
'release_id' => $id,
|
||||
]);
|
||||
@@ -1306,15 +1258,23 @@ class ElasticSearchDriver implements SearchDriverInterface
|
||||
'id' => $id,
|
||||
]);
|
||||
|
||||
} catch (Missing404Exception $e) {
|
||||
if (config('app.debug')) {
|
||||
Log::debug('ElasticSearch deletePreDb: document not found', ['predb_id' => $id]);
|
||||
}
|
||||
} catch (ElasticsearchException $e) {
|
||||
Log::error('ElasticSearch deletePreDb error: '.$e->getMessage(), [
|
||||
'predb_id' => $id,
|
||||
]);
|
||||
} catch (\Throwable $e) {
|
||||
if (ElasticsearchResponseHelper::isNotFound($e)) {
|
||||
if (config('app.debug')) {
|
||||
Log::debug('ElasticSearch deletePreDb: document not found', ['predb_id' => $id]);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($e instanceof ElasticsearchException) {
|
||||
Log::error('ElasticSearch deletePreDb error: '.$e->getMessage(), [
|
||||
'predb_id' => $id,
|
||||
]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Log::error('ElasticSearch deletePreDb unexpected error: '.$e->getMessage(), [
|
||||
'predb_id' => $id,
|
||||
]);
|
||||
@@ -1474,7 +1434,7 @@ class ElasticSearchDriver implements SearchDriverInterface
|
||||
try {
|
||||
$client = $this->getClient();
|
||||
|
||||
return $client->indices()->exists(['index' => $index]);
|
||||
return ElasticsearchResponseHelper::boolResponse($client, fn (Client $elasticClient) => $elasticClient->indices()->exists(['index' => $index]));
|
||||
} catch (\Throwable $e) {
|
||||
Log::error('ElasticSearch indexExists error: '.$e->getMessage(), ['index' => $index]);
|
||||
|
||||
@@ -1501,7 +1461,7 @@ class ElasticSearchDriver implements SearchDriverInterface
|
||||
$client = $this->getClient();
|
||||
|
||||
// Check if index exists
|
||||
if (! $client->indices()->exists(['index' => $index])) {
|
||||
if (! ElasticsearchResponseHelper::boolResponse($client, fn (Client $elasticClient) => $elasticClient->indices()->exists(['index' => $index]))) {
|
||||
Log::info("ElasticSearch truncateIndex: index {$index} does not exist, skipping");
|
||||
|
||||
continue;
|
||||
@@ -1577,7 +1537,7 @@ class ElasticSearchDriver implements SearchDriverInterface
|
||||
try {
|
||||
$client = $this->getClient();
|
||||
|
||||
return $client->cluster()->health();
|
||||
return ElasticsearchResponseHelper::asArray($client->cluster()->health());
|
||||
} catch (\Throwable $e) {
|
||||
Log::error('ElasticSearch getClusterHealth error: '.$e->getMessage());
|
||||
|
||||
@@ -1600,7 +1560,7 @@ class ElasticSearchDriver implements SearchDriverInterface
|
||||
try {
|
||||
$client = $this->getClient();
|
||||
|
||||
return $client->indices()->stats(['index' => $index]);
|
||||
return ElasticsearchResponseHelper::asArray($client->indices()->stats(['index' => $index]));
|
||||
} catch (\Throwable $e) {
|
||||
Log::error('ElasticSearch getIndexStats error: '.$e->getMessage(), ['index' => $index]);
|
||||
|
||||
@@ -1965,12 +1925,16 @@ class ElasticSearchDriver implements SearchDriverInterface
|
||||
'index' => $this->getMoviesIndex(),
|
||||
'id' => $id,
|
||||
]);
|
||||
} catch (Missing404Exception $e) {
|
||||
// Document doesn't exist, that's fine
|
||||
} catch (ElasticsearchException $e) {
|
||||
Log::error('ElasticSearch deleteMovie error: '.$e->getMessage(), [
|
||||
'id' => $id,
|
||||
]);
|
||||
} catch (\Throwable $e) {
|
||||
if (ElasticsearchResponseHelper::isNotFound($e)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($e instanceof ElasticsearchException) {
|
||||
Log::error('ElasticSearch deleteMovie error: '.$e->getMessage(), [
|
||||
'id' => $id,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2247,12 +2211,16 @@ class ElasticSearchDriver implements SearchDriverInterface
|
||||
'index' => $this->getTvShowsIndex(),
|
||||
'id' => $id,
|
||||
]);
|
||||
} catch (Missing404Exception $e) {
|
||||
// Document doesn't exist, that's fine
|
||||
} catch (ElasticsearchException $e) {
|
||||
Log::error('ElasticSearch deleteTvShow error: '.$e->getMessage(), [
|
||||
'id' => $id,
|
||||
]);
|
||||
} catch (\Throwable $e) {
|
||||
if (ElasticsearchResponseHelper::isNotFound($e)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($e instanceof ElasticsearchException) {
|
||||
Log::error('ElasticSearch deleteTvShow error: '.$e->getMessage(), [
|
||||
'id' => $id,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2513,7 +2481,6 @@ class ElasticSearchDriver implements SearchDriverInterface
|
||||
*
|
||||
* @param array<string, mixed> $categoryIds Array of category IDs to filter by
|
||||
* @param int $limit Maximum number of results
|
||||
* @return list
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function searchReleasesByCategory(array $categoryIds, int $limit = 1000): array
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Services\Search\Support;
|
||||
|
||||
use Elastic\Elasticsearch\Client;
|
||||
use Elastic\Elasticsearch\ClientBuilder;
|
||||
use GuzzleHttp\Client as GuzzleClient;
|
||||
use RuntimeException;
|
||||
|
||||
final class ElasticsearchClientFactory
|
||||
{
|
||||
/**
|
||||
* @param array<string, mixed> $config
|
||||
*/
|
||||
public static function make(array $config): Client
|
||||
{
|
||||
$hosts = self::buildHosts($config['hosts'] ?? []);
|
||||
|
||||
if ($hosts === []) {
|
||||
throw new RuntimeException('No Elasticsearch hosts configured');
|
||||
}
|
||||
|
||||
$builder = ClientBuilder::create()
|
||||
->setHosts($hosts)
|
||||
->setRetries((int) ($config['retries'] ?? 2));
|
||||
|
||||
$builder->setHttpClient(new GuzzleClient(self::buildHttpClientOptions($config)));
|
||||
|
||||
return $builder->build();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int, array<string, mixed>|string> $configHosts
|
||||
* @return list<string>
|
||||
*/
|
||||
public static function buildHosts(array $configHosts): array
|
||||
{
|
||||
$hosts = [];
|
||||
|
||||
foreach ($configHosts as $host) {
|
||||
if (is_string($host) && trim($host) !== '') {
|
||||
$hosts[] = $host;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! is_array($host)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$hostname = trim((string) ($host['host'] ?? ''));
|
||||
if ($hostname === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$scheme = trim((string) ($host['scheme'] ?? 'http')) ?: 'http';
|
||||
$port = $host['port'] ?? null;
|
||||
$portSuffix = $port !== null && $port !== '' ? ':'.(string) $port : '';
|
||||
$credentials = '';
|
||||
|
||||
if (! empty($host['user']) && ! empty($host['pass'])) {
|
||||
$credentials = rawurlencode((string) $host['user']).':'.rawurlencode((string) $host['pass']).'@';
|
||||
}
|
||||
|
||||
$hosts[] = sprintf('%s://%s%s%s', $scheme, $credentials, $hostname, $portSuffix);
|
||||
}
|
||||
|
||||
return $hosts;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $config
|
||||
* @return array<string, int|float|string|bool>
|
||||
*/
|
||||
public static function buildHttpClientOptions(array $config): array
|
||||
{
|
||||
$options = [];
|
||||
|
||||
$timeout = $config['timeout'] ?? null;
|
||||
if (is_numeric($timeout) && (float) $timeout > 0) {
|
||||
$options['timeout'] = (float) $timeout;
|
||||
}
|
||||
|
||||
$connectTimeout = $config['connect_timeout'] ?? null;
|
||||
if (is_numeric($connectTimeout) && (float) $connectTimeout > 0) {
|
||||
$options['connect_timeout'] = (float) $connectTimeout;
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Services\Search\Support;
|
||||
|
||||
use Elastic\Elasticsearch\Client;
|
||||
use Elastic\Elasticsearch\Exception\ClientResponseException;
|
||||
use Elastic\Elasticsearch\Response\Elasticsearch as ElasticsearchResponse;
|
||||
use Throwable;
|
||||
|
||||
final class ElasticsearchResponseHelper
|
||||
{
|
||||
/**
|
||||
* @param array<string, mixed>|ElasticsearchResponse $response
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public static function asArray(array|ElasticsearchResponse $response): array
|
||||
{
|
||||
return is_array($response) ? $response : $response->asArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a HEAD-style Elasticsearch call without throwing on 404.
|
||||
*
|
||||
* @param callable(Client): ElasticsearchResponse $callback
|
||||
*/
|
||||
public static function boolResponse(Client $client, callable $callback): bool
|
||||
{
|
||||
$previousSetting = $client->getResponseException();
|
||||
$client->setResponseException(false);
|
||||
|
||||
try {
|
||||
return $callback($client)->asBool();
|
||||
} finally {
|
||||
$client->setResponseException($previousSetting);
|
||||
}
|
||||
}
|
||||
|
||||
public static function isNotFound(Throwable $throwable): bool
|
||||
{
|
||||
return $throwable instanceof ClientResponseException && $throwable->getCode() === 404;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user