From ca6b2413e2286fd27db43dd6ffefbb3825a6ea4f Mon Sep 17 00:00:00 2001 From: Renan Bernordi Date: Thu, 28 Nov 2024 15:39:06 -0300 Subject: [PATCH] novo sistema de cache por disco ou s3 --- app/inc/Cache.php | 62 +++++------ app/inc/Cache/CacheStorageInterface.php | 31 ++++++ app/inc/Cache/DiskStorage.php | 67 ++++++++++++ app/inc/Cache/S3Storage.php | 140 ++++++++++++++++++++++++ 4 files changed, 264 insertions(+), 36 deletions(-) create mode 100644 app/inc/Cache/CacheStorageInterface.php create mode 100644 app/inc/Cache/DiskStorage.php create mode 100644 app/inc/Cache/S3Storage.php diff --git a/app/inc/Cache.php b/app/inc/Cache.php index b421148..e1d45f6 100644 --- a/app/inc/Cache.php +++ b/app/inc/Cache.php @@ -1,32 +1,45 @@ cacheDir = CACHE_DIR; - if (!file_exists($this->cacheDir)) { - mkdir($this->cacheDir, 0777, true); + // Se S3 está configurado e ativo, usa S3Storage + if (defined('S3_CACHE_ENABLED') && S3_CACHE_ENABLED === true) { + $this->storage = new S3Storage([ + 'key' => S3_ACCESS_KEY, + 'secret' => S3_SECRET_KEY, + 'bucket' => S3_BUCKET, + 'region' => S3_REGION ?? 'us-east-1', + 'prefix' => S3_PREFIX ?? 'cache/', + 'acl' => S3_ACL ?? 'private', + 'endpoint' => defined('S3_ENDPOINT') ? S3_ENDPOINT : null + ]); + } else { + // Caso contrário, usa o storage em disco + $this->storage = new DiskStorage(CACHE_DIR); } } @@ -57,9 +70,7 @@ class Cache return false; } - $id = $this->generateId($url); - $cachePath = $this->cacheDir . '/' . $id . '.gz'; - return file_exists($cachePath); + return $this->storage->exists($this->generateId($url)); } /** @@ -75,19 +86,7 @@ class Cache return null; } - if (!$this->exists($url)) { - return null; - } - $id = $this->generateId($url); - $cachePath = $this->cacheDir . '/' . $id . '.gz'; - - // Lê e descomprime o conteúdo - $compressedContent = file_get_contents($cachePath); - if ($compressedContent === false) { - return null; - } - - return gzdecode($compressedContent); + return $this->storage->get($this->generateId($url)); } /** @@ -104,15 +103,6 @@ class Cache return true; } - $id = $this->generateId($url); - $cachePath = $this->cacheDir . '/' . $id . '.gz'; - - // Comprime o conteúdo usando gzip - $compressedContent = gzencode($content, 3); - if ($compressedContent === false) { - return false; - } - - return file_put_contents($cachePath, $compressedContent) !== false; + return $this->storage->set($this->generateId($url), $content); } } diff --git a/app/inc/Cache/CacheStorageInterface.php b/app/inc/Cache/CacheStorageInterface.php new file mode 100644 index 0000000..89f2d2a --- /dev/null +++ b/app/inc/Cache/CacheStorageInterface.php @@ -0,0 +1,31 @@ +cacheDir = $cacheDir; + if (!file_exists($this->cacheDir)) { + mkdir($this->cacheDir, 0777, true); + } + } + + /** + * {@inheritdoc} + */ + public function exists(string $id): bool + { + $cachePath = $this->cacheDir . '/' . $id . '.gz'; + return file_exists($cachePath); + } + + /** + * {@inheritdoc} + */ + public function get(string $id): ?string + { + if (!$this->exists($id)) { + return null; + } + + $cachePath = $this->cacheDir . '/' . $id . '.gz'; + $compressedContent = file_get_contents($cachePath); + + if ($compressedContent === false) { + return null; + } + + return gzdecode($compressedContent); + } + + /** + * {@inheritdoc} + */ + public function set(string $id, string $content): bool + { + $cachePath = $this->cacheDir . '/' . $id . '.gz'; + $compressedContent = gzencode($content, 3); + + if ($compressedContent === false) { + return false; + } + + return file_put_contents($cachePath, $compressedContent) !== false; + } +} diff --git a/app/inc/Cache/S3Storage.php b/app/inc/Cache/S3Storage.php new file mode 100644 index 0000000..a965bfe --- /dev/null +++ b/app/inc/Cache/S3Storage.php @@ -0,0 +1,140 @@ + 'latest', + 'region' => $config['region'] ?? 'us-east-1', + 'credentials' => [ + 'key' => $config['key'], + 'secret' => $config['secret'], + ] + ]; + + // Adiciona endpoint personalizado se fornecido + if (!empty($config['endpoint'])) { + $clientConfig['endpoint'] = $config['endpoint']; + // Use path-style endpoints quando um endpoint personalizado é fornecido + $clientConfig['use_path_style_endpoint'] = true; + } + + $this->s3Client = new S3Client($clientConfig); + + $this->bucket = $config['bucket']; + $this->prefix = $config['prefix'] ?? 'cache/'; + $this->acl = $config['acl'] ?? 'private'; + } + + /** + * Gera a chave completa do objeto no S3 + * + * @param string $id ID do cache + * @return string + */ + private function getObjectKey(string $id): string + { + return $this->prefix . $id . '.gz'; + } + + /** + * {@inheritdoc} + */ + public function exists(string $id): bool + { + try { + return $this->s3Client->doesObjectExist( + $this->bucket, + $this->getObjectKey($id) + ); + } catch (AwsException $e) { + // Log error if needed + return false; + } + } + + /** + * {@inheritdoc} + */ + public function get(string $id): ?string + { + if (!$this->exists($id)) { + return null; + } + + try { + $result = $this->s3Client->getObject([ + 'Bucket' => $this->bucket, + 'Key' => $this->getObjectKey($id) + ]); + + $compressedContent = $result['Body']->getContents(); + + if ($compressedContent === false) { + return null; + } + + return $compressedContent; + } catch (AwsException $e) { + return null; + } + } + + /** + * {@inheritdoc} + */ + public function set(string $id, string $content): bool + { + try { + $compressedContent = gzencode($content, 3); + if ($compressedContent === false) { + return false; + } + + $this->s3Client->putObject([ + 'Bucket' => $this->bucket, + 'Key' => $this->getObjectKey($id), + 'Body' => $compressedContent, + 'ACL' => $this->acl, + 'ContentEncoding' => 'gzip', + 'CacheControl' => 'max-age=31536000' // 1 year + ]); + + return true; + } catch (AwsException $e) { + // Log error if needed + return false; + } + } +}