more consistent AbstractData implementation

This commit is contained in:
El RIDO 2021-06-16 05:19:45 +02:00
parent ae1e4e3edb
commit 3d9ba10fcb
No known key found for this signature in database
GPG Key ID: 0F5C940A6BD81F92
1 changed files with 66 additions and 46 deletions

View File

@ -9,6 +9,33 @@ use PrivateBin\Json;
class GoogleCloudStorage extends AbstractData class GoogleCloudStorage extends AbstractData
{ {
/**
* GCS client
*
* @access private
* @static
* @var StorageClient
*/
private static $_client = null;
/**
* GCS bucket
*
* @access private
* @static
* @var Bucket
*/
private static $_bucket = null;
/**
* object prefix
*
* @access private
* @static
* @var string
*/
private static $_prefix = 'pastes';
/** /**
* returns a Google Cloud Storage data backend. * returns a Google Cloud Storage data backend.
* *
@ -19,9 +46,12 @@ class GoogleCloudStorage extends AbstractData
*/ */
public static function getInstance(array $options) public static function getInstance(array $options)
{ {
$bucket = null; // if needed initialize the singleton
$prefix = 'pastes'; if (!(self::$_instance instanceof self)) {
self::$_instance = new self;
}
$bucket = null;
if (getenv('PRIVATEBIN_GCS_BUCKET')) { if (getenv('PRIVATEBIN_GCS_BUCKET')) {
$bucket = getenv('PRIVATEBIN_GCS_BUCKET'); $bucket = getenv('PRIVATEBIN_GCS_BUCKET');
} }
@ -29,46 +59,36 @@ class GoogleCloudStorage extends AbstractData
$bucket = $options['bucket']; $bucket = $options['bucket'];
} }
if (is_array($options) && array_key_exists('prefix', $options)) { if (is_array($options) && array_key_exists('prefix', $options)) {
$prefix = $options['prefix']; self::$_prefix = $options['prefix'];
} }
if (!(self::$_instance instanceof self)) { if (empty(self::$_client)) {
self::$_instance = new self($bucket, $prefix); self::$_client = class_exists('StorageClientStub', false) ?
new \StorageClientStub(array()) :
new StorageClient(array('suppressKeyFileNotice' => true));
} }
self::$_bucket = self::$_client->bucket($bucket);
return self::$_instance; return self::$_instance;
} }
protected $_client = null;
protected $_bucket = null;
protected $_prefix = 'pastes';
public function __construct($bucket, $prefix)
{
parent::__construct();
$this->_client = class_exists('StorageClientStub', false) ?
new \StorageClientStub(array()) :
new StorageClient(array('suppressKeyFileNotice' => true));
$this->_bucket = $this->_client->bucket($bucket);
if ($prefix != null) {
$this->_prefix = $prefix;
}
}
/** /**
* returns the google storage object key for $pasteid in $this->_bucket. * returns the google storage object key for $pasteid in self::$_bucket.
*
* @access private
* @param $pasteid string to get the key for * @param $pasteid string to get the key for
* @return string * @return string
*/ */
private function _getKey($pasteid) private function _getKey($pasteid)
{ {
if ($this->_prefix != '') { if (self::$_prefix != '') {
return $this->_prefix . '/' . $pasteid; return self::$_prefix . '/' . $pasteid;
} }
return $pasteid; return $pasteid;
} }
/** /**
* Uploads the payload in the $this->_bucket under the specified key. * Uploads the payload in the self::$_bucket under the specified key.
* The entire payload is stored as a JSON document. The metadata is replicated * The entire payload is stored as a JSON document. The metadata is replicated
* as the GCS object's metadata except for the fields attachment, attachmentname * as the GCS object's metadata except for the fields attachment, attachmentname
* and salt. * and salt.
@ -77,7 +97,7 @@ class GoogleCloudStorage extends AbstractData
* @param $payload array to store * @param $payload array to store
* @return bool true if successful, otherwise false. * @return bool true if successful, otherwise false.
*/ */
private function upload($key, $payload) private function _upload($key, $payload)
{ {
$metadata = array_key_exists('meta', $payload) ? $payload['meta'] : array(); $metadata = array_key_exists('meta', $payload) ? $payload['meta'] : array();
unset($metadata['attachment'], $metadata['attachmentname'], $metadata['salt']); unset($metadata['attachment'], $metadata['attachmentname'], $metadata['salt']);
@ -85,7 +105,7 @@ class GoogleCloudStorage extends AbstractData
$metadata[$k] = strval($v); $metadata[$k] = strval($v);
} }
try { try {
$this->_bucket->upload(Json::encode($payload), array( self::$_bucket->upload(Json::encode($payload), array(
'name' => $key, 'name' => $key,
'chunkSize' => 262144, 'chunkSize' => 262144,
'predefinedAcl' => 'private', 'predefinedAcl' => 'private',
@ -95,7 +115,7 @@ class GoogleCloudStorage extends AbstractData
), ),
)); ));
} catch (Exception $e) { } catch (Exception $e) {
error_log('failed to upload ' . $key . ' to ' . $this->_bucket->name() . ', ' . error_log('failed to upload ' . $key . ' to ' . self::$_bucket->name() . ', ' .
trim(preg_replace('/\s\s+/', ' ', $e->getMessage()))); trim(preg_replace('/\s\s+/', ' ', $e->getMessage())));
return false; return false;
} }
@ -111,7 +131,7 @@ class GoogleCloudStorage extends AbstractData
return false; return false;
} }
return $this->upload($this->_getKey($pasteid), $paste); return $this->_upload($this->_getKey($pasteid), $paste);
} }
/** /**
@ -120,13 +140,13 @@ class GoogleCloudStorage extends AbstractData
public function read($pasteid) public function read($pasteid)
{ {
try { try {
$o = $this->_bucket->object($this->_getKey($pasteid)); $o = self::$_bucket->object($this->_getKey($pasteid));
$data = $o->downloadAsString(); $data = $o->downloadAsString();
return Json::decode($data); return Json::decode($data);
} catch (NotFoundException $e) { } catch (NotFoundException $e) {
return false; return false;
} catch (Exception $e) { } catch (Exception $e) {
error_log('failed to read ' . $pasteid . ' from ' . $this->_bucket->name() . ', ' . error_log('failed to read ' . $pasteid . ' from ' . self::$_bucket->name() . ', ' .
trim(preg_replace('/\s\s+/', ' ', $e->getMessage()))); trim(preg_replace('/\s\s+/', ' ', $e->getMessage())));
return false; return false;
} }
@ -140,9 +160,9 @@ class GoogleCloudStorage extends AbstractData
$name = $this->_getKey($pasteid); $name = $this->_getKey($pasteid);
try { try {
foreach ($this->_bucket->objects(array('prefix' => $name . '/discussion/')) as $comment) { foreach (self::$_bucket->objects(array('prefix' => $name . '/discussion/')) as $comment) {
try { try {
$this->_bucket->object($comment->name())->delete(); self::$_bucket->object($comment->name())->delete();
} catch (NotFoundException $e) { } catch (NotFoundException $e) {
// ignore if already deleted. // ignore if already deleted.
} }
@ -152,7 +172,7 @@ class GoogleCloudStorage extends AbstractData
} }
try { try {
$this->_bucket->object($name)->delete(); self::$_bucket->object($name)->delete();
} catch (NotFoundException $e) { } catch (NotFoundException $e) {
// ignore if already deleted // ignore if already deleted
} }
@ -163,7 +183,7 @@ class GoogleCloudStorage extends AbstractData
*/ */
public function exists($pasteid) public function exists($pasteid)
{ {
$o = $this->_bucket->object($this->_getKey($pasteid)); $o = self::$_bucket->object($this->_getKey($pasteid));
return $o->exists(); return $o->exists();
} }
@ -176,7 +196,7 @@ class GoogleCloudStorage extends AbstractData
return false; return false;
} }
$key = $this->_getKey($pasteid) . '/discussion/' . $parentid . '/' . $commentid; $key = $this->_getKey($pasteid) . '/discussion/' . $parentid . '/' . $commentid;
return $this->upload($key, $comment); return $this->_upload($key, $comment);
} }
/** /**
@ -187,8 +207,8 @@ class GoogleCloudStorage extends AbstractData
$comments = array(); $comments = array();
$prefix = $this->_getKey($pasteid) . '/discussion/'; $prefix = $this->_getKey($pasteid) . '/discussion/';
try { try {
foreach ($this->_bucket->objects(array('prefix' => $prefix)) as $key) { foreach (self::$_bucket->objects(array('prefix' => $prefix)) as $key) {
$comment = JSON::decode($this->_bucket->object($key->name())->downloadAsString()); $comment = JSON::decode(self::$_bucket->object($key->name())->downloadAsString());
$comment['id'] = basename($key->name()); $comment['id'] = basename($key->name());
$slot = $this->getOpenSlot($comments, (int) $comment['meta']['created']); $slot = $this->getOpenSlot($comments, (int) $comment['meta']['created']);
$comments[$slot] = $comment; $comments[$slot] = $comment;
@ -205,7 +225,7 @@ class GoogleCloudStorage extends AbstractData
public function existsComment($pasteid, $parentid, $commentid) public function existsComment($pasteid, $parentid, $commentid)
{ {
$name = $this->_getKey($pasteid) . '/discussion/' . $parentid . '/' . $commentid; $name = $this->_getKey($pasteid) . '/discussion/' . $parentid . '/' . $commentid;
$o = $this->_bucket->object($name); $o = self::$_bucket->object($name);
return $o->exists(); return $o->exists();
} }
@ -216,7 +236,7 @@ class GoogleCloudStorage extends AbstractData
{ {
$path = 'config/' . $namespace; $path = 'config/' . $namespace;
try { try {
foreach ($this->_bucket->objects(array('prefix' => $path)) as $object) { foreach (self::$_bucket->objects(array('prefix' => $path)) as $object) {
$name = $object->name(); $name = $object->name();
if (strlen($name) > strlen($path) && substr($name, strlen($path), 1) !== '/') { if (strlen($name) > strlen($path) && substr($name, strlen($path), 1) !== '/') {
continue; continue;
@ -256,7 +276,7 @@ class GoogleCloudStorage extends AbstractData
$metadata['value'] = strval($value); $metadata['value'] = strval($value);
} }
try { try {
$this->_bucket->upload($value, array( self::$_bucket->upload($value, array(
'name' => $key, 'name' => $key,
'chunkSize' => 262144, 'chunkSize' => 262144,
'predefinedAcl' => 'private', 'predefinedAcl' => 'private',
@ -266,7 +286,7 @@ class GoogleCloudStorage extends AbstractData
), ),
)); ));
} catch (Exception $e) { } catch (Exception $e) {
error_log('failed to set key ' . $key . ' to ' . $this->_bucket->name() . ', ' . error_log('failed to set key ' . $key . ' to ' . self::$_bucket->name() . ', ' .
trim(preg_replace('/\s\s+/', ' ', $e->getMessage()))); trim(preg_replace('/\s\s+/', ' ', $e->getMessage())));
return false; return false;
} }
@ -284,7 +304,7 @@ class GoogleCloudStorage extends AbstractData
$key = 'config/' . $namespace . '/' . $key; $key = 'config/' . $namespace . '/' . $key;
} }
try { try {
$o = $this->_bucket->object($key); $o = self::$_bucket->object($key);
return $o->downloadAsString(); return $o->downloadAsString();
} catch (NotFoundException $e) { } catch (NotFoundException $e) {
return ''; return '';
@ -299,12 +319,12 @@ class GoogleCloudStorage extends AbstractData
$expired = array(); $expired = array();
$now = time(); $now = time();
$prefix = $this->_prefix; $prefix = self::$_prefix;
if ($prefix != '') { if ($prefix != '') {
$prefix = $prefix . '/'; $prefix .= '/';
} }
try { try {
foreach ($this->_bucket->objects(array('prefix' => $prefix)) as $object) { foreach (self::$_bucket->objects(array('prefix' => $prefix)) as $object) {
$metadata = $object->info()['metadata']; $metadata = $object->info()['metadata'];
if ($metadata != null && array_key_exists('expire_date', $metadata)) { if ($metadata != null && array_key_exists('expire_date', $metadata)) {
$expire_at = intval($metadata['expire_date']); $expire_at = intval($metadata['expire_date']);