Skip to content

Commit

Permalink
S3/Minio storage controller Support
Browse files Browse the repository at this point in the history
  • Loading branch information
geek-at committed Jan 5, 2020
1 parent 87fa55e commit f863045
Show file tree
Hide file tree
Showing 1,388 changed files with 75,681 additions and 2 deletions.
15 changes: 13 additions & 2 deletions rtfm/CONFIG.md
Expand Up @@ -3,7 +3,6 @@
|Option | value type | What it does|
|--- | --- | ---|
| URL | string | Sets the URL that will be shown to users for each upload. Must be set and must have tailing slash. eg: http://pictshare.local/ |
| ALT_FOLDER | string | All uploaded files will be copied to this location. This location can be a mounted network share (eg NFS or FTP, etc). If a file is not found in the normal upload direcotry, ALT_FOLDER will be checked. [more info about scaling PictShare](/rtfm/SCALING.md) |
| LOG_UPLOADER | bool | If set to true, all IP addresses of uploaders will be stored in /data/uploads.csv |
| FFMPEG_BINARY | string | If you installed ffmpeg on your machine, you can set the binary path here. This allows devices like the Raspberry Pi to be used with PictShare although I wouldn't recommend it because of the sloooooow conversion speed |
| PNG_COMPRESSION | int | 0 (no compression) to 9 (best compression) Note that for PNGs the compression doesn't affect the quality of the image, just the en/decode speed and file size |
Expand All @@ -15,4 +14,16 @@
| ALLOWED_SUBNET | IP addr | If set, will only show the upload form and allow to upload via API if request is coming from this subnet |
| UPLOAD_QUOTA (NOT IMPLEMENTED) | int | Size in MB. If set, will only allow uploads if combined size of uploads on Server is smaller than this value. Does not account for ALT_FOLDER data and resized versions of original uploads won't be added to calculation |
| UPLOAD_CODE (NOT IMPLEMENTED | string | If set, all uploads require this code via GET or POST variable "uploadcode" or upload will fail |
| MAX_RESIZED_IMAGES (NOT IMPLEMENTED | string | If set, limits count of resized images/videos per file on server |
| MAX_RESIZED_IMAGES (NOT IMPLEMENTED | string | If set, limits count of resized images/videos per file on server |

# Storage controllers

PictShare has an extention system that allows handling of multiple storage solutions or backends. You can configure them with the following settings

|Option | value type | What it does|
|--- | --- | ---|
| ALT_FOLDER | string | All uploaded files will be copied to this location. This location can be a mounted network share (eg NFS or FTP, etc). If a file is not found in the normal upload direcotry, ALT_FOLDER will be checked. [more info about scaling PictShare](/rtfm/SCALING.md) |
|S3_BUCKET | string | Name of your [S3 bucket](https://aws.amazon.com/s3/) |
|S3_ACCESS_KEY | string | Access key for your bucket|
|S3_SECRET_KEY | string | Secret key for your bucket
|S3_ENDPOINT | URL | Server URL. If you're using S3 compatible software like [Minio](https://min.io/) you can enter the URL here |
76 changes: 76 additions & 0 deletions storage-controllers/s3.controller.php
@@ -0,0 +1,76 @@
<?php

/**
* Config needed
*
* S3_BUCKET
* S3_ACCESS_KEY
* S3_SECRET_KEY
* (optional) S3_ENDPOINT
*/

class S3Storage //implements StorageController
{
private $s3;
function connect(){
require ROOT.DS.'storage-controllers'.DS.'s3'.DS.'aws-autoloader.php';
$this->s3 = new Aws\S3\S3Client([
'version' => 'latest',
'region' => 'us-east-1',
'endpoint' => S3_ENDPOINT,
'use_path_style_endpoint' => true,
'credentials' => [
'key' => S3_ACCESS_KEY,
'secret' => S3_SECRET_KEY,
],
]);
}

function isEnabled()
{
return (defined('S3_BUCKET') && S3_BUCKET);
}

function hashExists($hash)
{
if(!$this->s3)$this->connect();

return $this->s3->doesObjectExist(S3_BUCKET,$hash);
}

function pullFile($hash)
{
if(!$this->s3)$this->connect();

if(!$this->hashExists($hash)) return false;
$this->s3->getObject([
'Bucket' => S3_BUCKET,
'Key' => $hash,
'SaveAs' => ROOT.DS.'data'.DS.$hash.DS.$hash
]);
return true;
}

function pushFile($hash)
{
if(!$this->s3)$this->connect();

$this->s3->putObject([
'Bucket' => S3_BUCKET,
'Key' => $hash,
'SourceFile' => ROOT.DS.'data'.DS.$hash.DS.$hash
]);

return true;
}

function deleteFile($hash)
{
if(!$this->s3)$this->connect();

$this->s3->deleteObject([
'Bucket' => S3_BUCKET,
'Key' => $hash
]);
}
}
49 changes: 49 additions & 0 deletions storage-controllers/s3/Aws/ACMPCA/ACMPCAClient.php
@@ -0,0 +1,49 @@
<?php
namespace Aws\ACMPCA;

use Aws\AwsClient;

/**
* This client is used to interact with the **AWS Certificate Manager Private Certificate Authority** service.
* @method \Aws\Result createCertificateAuthority(array $args = [])
* @method \GuzzleHttp\Promise\Promise createCertificateAuthorityAsync(array $args = [])
* @method \Aws\Result createCertificateAuthorityAuditReport(array $args = [])
* @method \GuzzleHttp\Promise\Promise createCertificateAuthorityAuditReportAsync(array $args = [])
* @method \Aws\Result createPermission(array $args = [])
* @method \GuzzleHttp\Promise\Promise createPermissionAsync(array $args = [])
* @method \Aws\Result deleteCertificateAuthority(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteCertificateAuthorityAsync(array $args = [])
* @method \Aws\Result deletePermission(array $args = [])
* @method \GuzzleHttp\Promise\Promise deletePermissionAsync(array $args = [])
* @method \Aws\Result describeCertificateAuthority(array $args = [])
* @method \GuzzleHttp\Promise\Promise describeCertificateAuthorityAsync(array $args = [])
* @method \Aws\Result describeCertificateAuthorityAuditReport(array $args = [])
* @method \GuzzleHttp\Promise\Promise describeCertificateAuthorityAuditReportAsync(array $args = [])
* @method \Aws\Result getCertificate(array $args = [])
* @method \GuzzleHttp\Promise\Promise getCertificateAsync(array $args = [])
* @method \Aws\Result getCertificateAuthorityCertificate(array $args = [])
* @method \GuzzleHttp\Promise\Promise getCertificateAuthorityCertificateAsync(array $args = [])
* @method \Aws\Result getCertificateAuthorityCsr(array $args = [])
* @method \GuzzleHttp\Promise\Promise getCertificateAuthorityCsrAsync(array $args = [])
* @method \Aws\Result importCertificateAuthorityCertificate(array $args = [])
* @method \GuzzleHttp\Promise\Promise importCertificateAuthorityCertificateAsync(array $args = [])
* @method \Aws\Result issueCertificate(array $args = [])
* @method \GuzzleHttp\Promise\Promise issueCertificateAsync(array $args = [])
* @method \Aws\Result listCertificateAuthorities(array $args = [])
* @method \GuzzleHttp\Promise\Promise listCertificateAuthoritiesAsync(array $args = [])
* @method \Aws\Result listPermissions(array $args = [])
* @method \GuzzleHttp\Promise\Promise listPermissionsAsync(array $args = [])
* @method \Aws\Result listTags(array $args = [])
* @method \GuzzleHttp\Promise\Promise listTagsAsync(array $args = [])
* @method \Aws\Result restoreCertificateAuthority(array $args = [])
* @method \GuzzleHttp\Promise\Promise restoreCertificateAuthorityAsync(array $args = [])
* @method \Aws\Result revokeCertificate(array $args = [])
* @method \GuzzleHttp\Promise\Promise revokeCertificateAsync(array $args = [])
* @method \Aws\Result tagCertificateAuthority(array $args = [])
* @method \GuzzleHttp\Promise\Promise tagCertificateAuthorityAsync(array $args = [])
* @method \Aws\Result untagCertificateAuthority(array $args = [])
* @method \GuzzleHttp\Promise\Promise untagCertificateAuthorityAsync(array $args = [])
* @method \Aws\Result updateCertificateAuthority(array $args = [])
* @method \GuzzleHttp\Promise\Promise updateCertificateAuthorityAsync(array $args = [])
*/
class ACMPCAClient extends AwsClient {}
@@ -0,0 +1,9 @@
<?php
namespace Aws\ACMPCA\Exception;

use Aws\Exception\AwsException;

/**
* Represents an error interacting with the **AWS Certificate Manager Private Certificate Authority** service.
*/
class ACMPCAException extends AwsException {}
142 changes: 142 additions & 0 deletions storage-controllers/s3/Aws/AbstractConfigurationProvider.php
@@ -0,0 +1,142 @@
<?php
namespace Aws;

use GuzzleHttp\Promise;

/**
* A configuration provider is a function that returns a promise that is
* fulfilled with a configuration object. This class provides base functionality
* usable by specific configuration provider implementations
*/
abstract class AbstractConfigurationProvider
{
const ENV_PROFILE = 'AWS_PROFILE';

public static $cacheKey;

protected static $interfaceClass;
protected static $exceptionClass;

/**
* Wraps a config provider and saves provided configuration in an
* instance of Aws\CacheInterface. Forwards calls when no config found
* in cache and updates cache with the results.
*
* @param callable $provider Configuration provider function to wrap
* @param CacheInterface $cache Cache to store configuration
* @param string|null $cacheKey (optional) Cache key to use
*
* @return callable
*/
public static function cache(
callable $provider,
CacheInterface $cache,
$cacheKey = null
) {
$cacheKey = $cacheKey ?: static::$cacheKey;

return function () use ($provider, $cache, $cacheKey) {
$found = $cache->get($cacheKey);
if ($found instanceof static::$interfaceClass) {
return Promise\promise_for($found);
}

return $provider()
->then(function ($config) use (
$cache,
$cacheKey
) {
$cache->set($cacheKey, $config);
return $config;
});
};
}

/**
* Creates an aggregate configuration provider that invokes the provided
* variadic providers one after the other until a provider returns
* configuration.
*
* @return callable
*/
public static function chain()
{
$links = func_get_args();
if (empty($links)) {
throw new \InvalidArgumentException('No providers in chain');
}

return function () use ($links) {
/** @var callable $parent */
$parent = array_shift($links);
$promise = $parent();
while ($next = array_shift($links)) {
$promise = $promise->otherwise($next);
}
return $promise;
};
}

/**
* Gets the environment's HOME directory if available.
*
* @return null|string
*/
protected static function getHomeDir()
{
// On Linux/Unix-like systems, use the HOME environment variable
if ($homeDir = getenv('HOME')) {
return $homeDir;
}

// Get the HOMEDRIVE and HOMEPATH values for Windows hosts
$homeDrive = getenv('HOMEDRIVE');
$homePath = getenv('HOMEPATH');

return ($homeDrive && $homePath) ? $homeDrive . $homePath : null;
}

/**
* Wraps a config provider and caches previously provided configuration.
*
* @param callable $provider Config provider function to wrap.
*
* @return callable
*/
public static function memoize(callable $provider)
{
return function () use ($provider) {
static $result;
static $isConstant;

// Constant config will be returned constantly.
if ($isConstant) {
return $result;
}

// Create the initial promise that will be used as the cached value
if (null === $result) {
$result = $provider();
}

// Return config and set flag that provider is already set
return $result
->then(function ($config) use (&$isConstant) {
$isConstant = true;
return $config;
});
};
}

/**
* Reject promise with standardized exception.
*
* @param $msg
* @return Promise\RejectedPromise
*/
protected static function reject($msg)
{
$exceptionClass = static::$exceptionClass;
return new Promise\RejectedPromise(new $exceptionClass($msg));
}
}
45 changes: 45 additions & 0 deletions storage-controllers/s3/Aws/AccessAnalyzer/AccessAnalyzerClient.php
@@ -0,0 +1,45 @@
<?php
namespace Aws\AccessAnalyzer;

use Aws\AwsClient;

/**
* This client is used to interact with the **Access Analyzer** service.
* @method \Aws\Result createAnalyzer(array $args = [])
* @method \GuzzleHttp\Promise\Promise createAnalyzerAsync(array $args = [])
* @method \Aws\Result createArchiveRule(array $args = [])
* @method \GuzzleHttp\Promise\Promise createArchiveRuleAsync(array $args = [])
* @method \Aws\Result deleteAnalyzer(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteAnalyzerAsync(array $args = [])
* @method \Aws\Result deleteArchiveRule(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteArchiveRuleAsync(array $args = [])
* @method \Aws\Result getAnalyzedResource(array $args = [])
* @method \GuzzleHttp\Promise\Promise getAnalyzedResourceAsync(array $args = [])
* @method \Aws\Result getAnalyzer(array $args = [])
* @method \GuzzleHttp\Promise\Promise getAnalyzerAsync(array $args = [])
* @method \Aws\Result getArchiveRule(array $args = [])
* @method \GuzzleHttp\Promise\Promise getArchiveRuleAsync(array $args = [])
* @method \Aws\Result getFinding(array $args = [])
* @method \GuzzleHttp\Promise\Promise getFindingAsync(array $args = [])
* @method \Aws\Result listAnalyzedResources(array $args = [])
* @method \GuzzleHttp\Promise\Promise listAnalyzedResourcesAsync(array $args = [])
* @method \Aws\Result listAnalyzers(array $args = [])
* @method \GuzzleHttp\Promise\Promise listAnalyzersAsync(array $args = [])
* @method \Aws\Result listArchiveRules(array $args = [])
* @method \GuzzleHttp\Promise\Promise listArchiveRulesAsync(array $args = [])
* @method \Aws\Result listFindings(array $args = [])
* @method \GuzzleHttp\Promise\Promise listFindingsAsync(array $args = [])
* @method \Aws\Result listTagsForResource(array $args = [])
* @method \GuzzleHttp\Promise\Promise listTagsForResourceAsync(array $args = [])
* @method \Aws\Result startResourceScan(array $args = [])
* @method \GuzzleHttp\Promise\Promise startResourceScanAsync(array $args = [])
* @method \Aws\Result tagResource(array $args = [])
* @method \GuzzleHttp\Promise\Promise tagResourceAsync(array $args = [])
* @method \Aws\Result untagResource(array $args = [])
* @method \GuzzleHttp\Promise\Promise untagResourceAsync(array $args = [])
* @method \Aws\Result updateArchiveRule(array $args = [])
* @method \GuzzleHttp\Promise\Promise updateArchiveRuleAsync(array $args = [])
* @method \Aws\Result updateFindings(array $args = [])
* @method \GuzzleHttp\Promise\Promise updateFindingsAsync(array $args = [])
*/
class AccessAnalyzerClient extends AwsClient {}
@@ -0,0 +1,9 @@
<?php
namespace Aws\AccessAnalyzer\Exception;

use Aws\Exception\AwsException;

/**
* Represents an error interacting with the **Access Analyzer** service.
*/
class AccessAnalyzerException extends AwsException {}

0 comments on commit f863045

Please sign in to comment.