Skip to content

Commit

Permalink
Merge pull request #1236 from nupplaphil/feat/s3
Browse files Browse the repository at this point in the history
Add S3 Storage Backend
  • Loading branch information
MrPetovan authored Feb 25, 2022
2 parents 95fcf98 + 3425cd3 commit 3317ce2
Show file tree
Hide file tree
Showing 63 changed files with 8,107 additions and 0 deletions.
23 changes: 23 additions & 0 deletions s3_storage/composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"name": "friendica-addons/s3_storage",
"description": "Adds the possibility to use S3 as a selectable storage backend",
"type": "friendica-addon",
"authors": [
{
"name": "Philipp Holzer",
"email": "[email protected]",
"homepage": "https://blog.philipp.info",
"role": "Developer"
}
],
"require": {
"php": ">=7.0",
"akeeba/s3": "^2.0"
},
"license": "3-clause BSD license",
"config": {
"optimize-autoloader": true,
"autoloader-suffix": "S3StorageAddon",
"preferred-install": "dist"
}
}
65 changes: 65 additions & 0 deletions s3_storage/composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

108 changes: 108 additions & 0 deletions s3_storage/lang/C/messages.po
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
# ADDON s3_storage
# Copyright (C)
# This file is distributed under the same license as the Friendica s3_storage addon package.
#
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-02-24 23:25+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <[email protected]>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"

#: src/S3Config.php:113
msgid "Access Key"
msgstr ""

#: src/S3Config.php:115
msgid "Set the Access Key of the S3 storage"
msgstr ""

#: src/S3Config.php:120
msgid "Secret Key"
msgstr ""

#: src/S3Config.php:122
msgid "Set the Secret Key of the S3 storage"
msgstr ""

#: src/S3Config.php:127
msgid "Bucket"
msgstr ""

#: src/S3Config.php:129
msgid "The S3 Bucket (name), you want to use with Friendica"
msgstr ""

#: src/S3Config.php:134
msgid "Signature Method"
msgstr ""

#: src/S3Config.php:136
msgid ""
"Set the signature method to use (BEWARE: v4 will be automatically set to v2 "
"in case the endpoint isn't amazon)"
msgstr ""

#: src/S3Config.php:141
#, php-format
msgid "Amazon S3 compatible endpoint (leave empty for '%s')"
msgstr ""

#: src/S3Config.php:143
msgid ""
"Set the S3 endpoint. Do NOT use a protocol (You can use a custom endpoint "
"with v2 signatures to access third party services which offer S3 "
"compatibility, e.g. OwnCloud, Google Storage etc.)"
msgstr ""

#: src/S3Config.php:147
#, php-format
msgid "AWS region (leave empty for '%s')"
msgstr ""

#: src/S3Config.php:149
msgid "The AWS region is mandatory for v4 signatures"
msgstr ""

#: src/S3Config.php:153
msgid "Use the dualstack URL (which will ship traffic over ipv6 in most cases)"
msgstr ""

#: src/S3Config.php:155
msgid ""
"For more information on these endpoints please read https://docs.aws.amazon."
"com/AmazonS3/latest/dev/dual-stack-endpoints.html"
msgstr ""

#: src/S3Config.php:159
msgid "Use legacy, path-style access to the bucket"
msgstr ""

#: src/S3Config.php:161
msgid ""
"When it's turned off (default) we use virtual hosting stylepaths which are "
"RECOMMENDED BY AMAZON per http://docs.aws.amazon.com/AmazonS3/latest/API/"
"APIRest.html"
msgstr ""

#: src/S3Config.php:175
msgid "Invalid input"
msgstr ""

#: src/S3Config.php:214
#, php-format
msgid "error '%s', message '%s'"
msgstr ""

#: src/S3Config.php:222
#, php-format
msgid "Bucket %s cannot be not found, possible buckets: %s"
msgstr ""
42 changes: 42 additions & 0 deletions s3_storage/s3_storage.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php
/*
* Name: S3 Storage
* Description: Adds the possibility to use Amazon S3 as a selectable storage backend
* Version: 1.0
* Author: Philipp Holzer
*/

use Friendica\Addon\s3_storage\src\S3Client;
use Friendica\Addon\s3_storage\src\S3Config;
use Friendica\App;
use Friendica\Core\Hook;
use Friendica\DI;

require_once __DIR__ . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php';

function s3_storage_install($a)
{
Hook::register('storage_instance' , __FILE__, 's3_storage_instance');
Hook::register('storage_config' , __FILE__, 's3_storage_config');
DI::storageManager()->register(S3Client::class);
}

function s3_storage_uninstall()
{
DI::storageManager()->unregister(S3Client::class);
}

function s3_storage_instance(App $a, array &$data)
{
if ($data['name'] == S3Client::getName()) {
$config = new S3Config(DI::l10n(), DI::config());
$data['storage'] = new S3Client($config->getConfig(), $config->getBucket());
}
}

function s3_storage_config(App $a, array &$data)
{
if ($data['name'] == S3Client::getName()) {
$data['storage_config'] = new S3Config(DI::l10n(), DI::config());
}
}
101 changes: 101 additions & 0 deletions s3_storage/src/S3Client.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
<?php

namespace Friendica\Addon\s3_storage\src;

defined('AKEEBAENGINE') or define('AKEEBAENGINE', 1);

use Akeeba\Engine\Postproc\Connector\S3v4\Configuration;
use Akeeba\Engine\Postproc\Connector\S3v4\Connector;
use Akeeba\Engine\Postproc\Connector\S3v4\Exception\CannotDeleteFile;
use Akeeba\Engine\Postproc\Connector\S3v4\Input;
use Friendica\Core\Storage\Capability\ICanWriteToStorage;
use Friendica\Core\Storage\Exception\StorageException;
use Friendica\Util\Strings;

/**
* A WebDav Backend Storage class
*/
class S3Client implements ICanWriteToStorage
{
const NAME = 'S3';

/** @var Connector */
protected $connector;

/** @var string The name of the bucket used for the backend */
protected $bucket;

public function __construct(Configuration $config, string $bucket)
{
$this->connector = new Connector($config);
$this->bucket = $bucket;
}

/**
* Split data ref and return file path
*
* @param string $reference Data reference
*
* @return string
*/
private function pathForRef(string $reference): string
{
$fold1 = substr($reference, 0, 2);
$fold2 = substr($reference, 2, 2);
$file = substr($reference, 4);

return implode('/', [$fold1, $fold2, $file]);
}

/** {@inheritDoc} */
public function __toString(): string
{
return self::getName();
}

/** {@inheritDoc} */
public static function getName(): string
{
return self::NAME;
}

/** {@inheritDoc} */
public function get(string $reference): string
{
try {
return $this->connector->getObject($this->bucket, $this->pathForRef($reference), false);
} catch (\RuntimeException $exception) {
throw new StorageException(sprintf('Cannot get reference %s', $reference), $exception->getCode(), $exception);
}
}

/** {@inheritDoc} */
public function put(string $data, string $reference = ""): string
{
if ($reference === '') {
try {
$reference = Strings::getRandomHex();
} catch (\Exception $exception) {
throw new StorageException('S3 storage failed to generate a random hex', $exception->getCode(), $exception);
}
}

try {
$input = Input::createFromData($data);
$this->connector->putObject($input, $this->bucket, $this->pathForRef($reference));
return $reference;
} catch (\Exception $exception) {
throw new StorageException(sprintf('Cannot put data for reference %s', $reference), $exception->getCode(), $exception);
}
}

/** {@inheritDoc} */
public function delete(string $reference)
{
try {
$this->connector->deleteObject($this->bucket, $this->pathForRef($reference));
} catch (CannotDeleteFile $exception) {
throw new StorageException(sprintf('Cannot delete reference %s', $reference), $exception->getCode(), $exception);
}
}
}
Loading

0 comments on commit 3317ce2

Please sign in to comment.