Skip to content

Commit 6d232fa

Browse files
committed
feat(s3): add generic S3 device
1 parent 1cf4554 commit 6d232fa

12 files changed

Lines changed: 500 additions & 473 deletions

File tree

.github/workflows/tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ jobs:
5858
strategy:
5959
fail-fast: false
6060
matrix:
61-
devices: [BackblazeTest, DOSpacesTest, LinodeTest, LocalTest, S3Test, WasabiTest]
61+
devices: [BackblazeTest, DOSpacesTest, LinodeTest, LocalTest, AWSTest, WasabiTest]
6262

6363
steps:
6464
- name: checkout

composer.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@
2121
"ext-zstd": "*",
2222
"ext-xz": "*",
2323
"ext-brotli": "*",
24+
"ext-curl": "*",
2425
"ext-lz4": "*",
26+
"ext-simplexml": "*",
2527
"ext-snappy": "*",
2628
"php": ">=8.0",
2729
"utopia-php/framework": "0.*.*",

composer.lock

Lines changed: 362 additions & 382 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Storage/Device/AWS.php

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
<?php
2+
3+
namespace Utopia\Storage\Device;
4+
5+
use Utopia\Storage\Storage;
6+
7+
class AWS extends S3
8+
{
9+
/**
10+
* AWS Regions constants
11+
*/
12+
const US_EAST_1 = 'us-east-1';
13+
14+
const US_EAST_2 = 'us-east-2';
15+
16+
const US_WEST_1 = 'us-west-1';
17+
18+
const US_WEST_2 = 'us-west-2';
19+
20+
const AF_SOUTH_1 = 'af-south-1';
21+
22+
const AP_EAST_1 = 'ap-east-1';
23+
24+
const AP_SOUTH_1 = 'ap-south-1';
25+
26+
const AP_NORTHEAST_3 = 'ap-northeast-3';
27+
28+
const AP_NORTHEAST_2 = 'ap-northeast-2';
29+
30+
const AP_NORTHEAST_1 = 'ap-northeast-1';
31+
32+
const AP_SOUTHEAST_1 = 'ap-southeast-1';
33+
34+
const AP_SOUTHEAST_2 = 'ap-southeast-2';
35+
36+
const CA_CENTRAL_1 = 'ca-central-1';
37+
38+
const EU_CENTRAL_1 = 'eu-central-1';
39+
40+
const EU_WEST_1 = 'eu-west-1';
41+
42+
const EU_SOUTH_1 = 'eu-south-1';
43+
44+
const EU_WEST_2 = 'eu-west-2';
45+
46+
const EU_WEST_3 = 'eu-west-3';
47+
48+
const EU_NORTH_1 = 'eu-north-1';
49+
50+
const SA_EAST_1 = 'eu-north-1';
51+
52+
const CN_NORTH_1 = 'cn-north-1';
53+
54+
const CN_NORTH_4 = 'cn-north-4';
55+
56+
const CN_NORTHWEST_1 = 'cn-northwest-1';
57+
58+
const ME_SOUTH_1 = 'me-south-1';
59+
60+
const US_GOV_EAST_1 = 'us-gov-east-1';
61+
62+
const US_GOV_WEST_1 = 'us-gov-west-1';
63+
64+
/**
65+
* S3 Constructor
66+
*
67+
* @param string $root
68+
* @param string $accessKey
69+
* @param string $secretKey
70+
* @param string $bucket
71+
* @param string $region
72+
* @param string $acl
73+
*/
74+
public function __construct(string $root, string $accessKey, string $secretKey, string $bucket, string $region = self::US_EAST_1, string $acl = self::ACL_PRIVATE)
75+
{
76+
$host = match ($region) {
77+
self::CN_NORTH_1, self::CN_NORTH_4, self::CN_NORTHWEST_1 => $bucket.'.s3.'.$region.'.amazonaws.cn',
78+
default => $bucket.'.s3.'.$region.'.amazonaws.com'
79+
};
80+
parent::__construct($root, $accessKey, $secretKey, $host, $region, $acl);
81+
}
82+
83+
/**
84+
* @return string
85+
*/
86+
public function getName(): string
87+
{
88+
return 'AWS S3 Storage';
89+
}
90+
91+
/**
92+
* @return string
93+
*/
94+
public function getType(): string
95+
{
96+
return Storage::DEVICE_AWS_S3;
97+
}
98+
99+
/**
100+
* @return string
101+
*/
102+
public function getDescription(): string
103+
{
104+
return 'S3 Bucket Storage drive for AWS';
105+
}
106+
}

src/Storage/Device/Backblaze.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ class Backblaze extends S3
3434
*/
3535
public function __construct(string $root, string $accessKey, string $secretKey, string $bucket, string $region = self::US_WEST_004, string $acl = self::ACL_PRIVATE)
3636
{
37-
parent::__construct($root, $accessKey, $secretKey, $bucket, $region, $acl);
38-
$this->headers['host'] = $bucket.'.'.'s3'.'.'.$region.'.backblazeb2.com';
37+
$host = $bucket.'.'.'s3'.'.'.$region.'.backblazeb2.com';
38+
parent::__construct($root, $accessKey, $secretKey, $host, $region, $acl);
3939
}
4040

4141
/**

src/Storage/Device/DOSpaces.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ class DOSpaces extends S3
3333
*/
3434
public function __construct(string $root, string $accessKey, string $secretKey, string $bucket, string $region = self::NYC3, string $acl = self::ACL_PRIVATE)
3535
{
36-
parent::__construct($root, $accessKey, $secretKey, $bucket, $region, $acl);
37-
$this->headers['host'] = $bucket.'.'.$region.'.digitaloceanspaces.com';
36+
$host = $bucket.'.'.$region.'.digitaloceanspaces.com';
37+
parent::__construct($root, $accessKey, $secretKey, $host, $region, $acl);
3838
}
3939

4040
/**

src/Storage/Device/Linode.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ class Linode extends S3
2929
*/
3030
public function __construct(string $root, string $accessKey, string $secretKey, string $bucket, string $region = self::EU_CENTRAL_1, string $acl = self::ACL_PRIVATE)
3131
{
32-
parent::__construct($root, $accessKey, $secretKey, $bucket, $region, $acl);
33-
$this->headers['host'] = $bucket.'.'.$region.'.'.'linodeobjects.com';
32+
$host = $bucket.'.'.$region.'.'.'linodeobjects.com';
33+
parent::__construct($root, $accessKey, $secretKey, $host, $region, $acl);
3434
}
3535

3636
/**

src/Storage/Device/S3.php

Lines changed: 11 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -34,61 +34,6 @@ class S3 extends Device
3434

3535
const HTTP_VERSION_1_0 = CURL_HTTP_VERSION_1_0;
3636

37-
/**
38-
* AWS Regions constants
39-
*/
40-
const US_EAST_1 = 'us-east-1';
41-
42-
const US_EAST_2 = 'us-east-2';
43-
44-
const US_WEST_1 = 'us-west-1';
45-
46-
const US_WEST_2 = 'us-west-2';
47-
48-
const AF_SOUTH_1 = 'af-south-1';
49-
50-
const AP_EAST_1 = 'ap-east-1';
51-
52-
const AP_SOUTH_1 = 'ap-south-1';
53-
54-
const AP_NORTHEAST_3 = 'ap-northeast-3';
55-
56-
const AP_NORTHEAST_2 = 'ap-northeast-2';
57-
58-
const AP_NORTHEAST_1 = 'ap-northeast-1';
59-
60-
const AP_SOUTHEAST_1 = 'ap-southeast-1';
61-
62-
const AP_SOUTHEAST_2 = 'ap-southeast-2';
63-
64-
const CA_CENTRAL_1 = 'ca-central-1';
65-
66-
const EU_CENTRAL_1 = 'eu-central-1';
67-
68-
const EU_WEST_1 = 'eu-west-1';
69-
70-
const EU_SOUTH_1 = 'eu-south-1';
71-
72-
const EU_WEST_2 = 'eu-west-2';
73-
74-
const EU_WEST_3 = 'eu-west-3';
75-
76-
const EU_NORTH_1 = 'eu-north-1';
77-
78-
const SA_EAST_1 = 'eu-north-1';
79-
80-
const CN_NORTH_1 = 'cn-north-1';
81-
82-
const CN_NORTH_4 = 'cn-north-4';
83-
84-
const CN_NORTHWEST_1 = 'cn-northwest-1';
85-
86-
const ME_SOUTH_1 = 'me-south-1';
87-
88-
const US_GOV_EAST_1 = 'us-gov-east-1';
89-
90-
const US_GOV_WEST_1 = 'us-gov-west-1';
91-
9237
/**
9338
* AWS ACL Flag constants
9439
*/
@@ -116,11 +61,6 @@ class S3 extends Device
11661
*/
11762
protected string $secretKey;
11863

119-
/**
120-
* @var string
121-
*/
122-
protected string $bucket;
123-
12464
/**
12565
* @var string
12666
*/
@@ -146,6 +86,8 @@ class S3 extends Device
14686
'content-type' => '',
14787
];
14888

89+
protected string $fqdn;
90+
14991
/**
15092
* @var array
15193
*/
@@ -164,30 +106,25 @@ class S3 extends Device
164106
* @param string $root
165107
* @param string $accessKey
166108
* @param string $secretKey
167-
* @param string $bucket
168109
* @param string $region
169110
* @param string $acl
170111
*/
171-
public function __construct(string $root, string $accessKey, string $secretKey, string $bucket, string $region = self::US_EAST_1, string $acl = self::ACL_PRIVATE, $endpointUrl = '')
112+
public function __construct(string $root, string $accessKey, string $secretKey, string $host, string $region, string $acl = self::ACL_PRIVATE)
172113
{
173114
$this->accessKey = $accessKey;
174115
$this->secretKey = $secretKey;
175-
$this->bucket = $bucket;
176116
$this->region = $region;
177117
$this->root = $root;
178118
$this->acl = $acl;
179119
$this->amzHeaders = [];
180120

181-
if (! empty($endpointUrl)) {
182-
$host = $bucket.'.'.$endpointUrl;
121+
if (str_starts_with($host, 'http://') || str_starts_with($host, 'https://')) {
122+
$this->fqdn = $host;
123+
$this->headers['host'] = str_replace(['http://', 'https://'], '', $host);
183124
} else {
184-
$host = match ($region) {
185-
self::CN_NORTH_1, self::CN_NORTH_4, self::CN_NORTHWEST_1 => $bucket.'.s3.'.$region.'.amazonaws.cn',
186-
default => $bucket.'.s3.'.$region.'.amazonaws.com'
187-
};
125+
$this->fqdn = 'https://'.$host;
126+
$this->headers['host'] = $host;
188127
}
189-
190-
$this->headers['host'] = $host;
191128
}
192129

193130
/**
@@ -211,7 +148,7 @@ public function getType(): string
211148
*/
212149
public function getDescription(): string
213150
{
214-
return 'S3 Bucket Storage drive for AWS or on premise solution';
151+
return 'S3 Storage drive for generic S3-compatible provider';
215152
}
216153

217154
/**
@@ -869,7 +806,7 @@ private function getSignatureV4(string $method, string $uri, array $parameters =
869806
protected function call(string $method, string $uri, string $data = '', array $parameters = [], bool $decode = true)
870807
{
871808
$uri = $this->getAbsolutePath($uri);
872-
$url = 'https://'.$this->headers['host'].$uri.'?'.\http_build_query($parameters, '', '&', PHP_QUERY_RFC3986);
809+
$url = $this->fqdn.$uri.'?'.\http_build_query($parameters, '', '&', PHP_QUERY_RFC3986);
873810
$response = new \stdClass;
874811
$response->body = '';
875812
$response->headers = [];
@@ -983,7 +920,7 @@ protected function call(string $method, string $uri, string $data = '', array $p
983920
* @param string $b String B
984921
* @return int
985922
*/
986-
private function sortMetaHeadersCmp($a, $b)
923+
protected function sortMetaHeadersCmp(string $a, string $b): int
987924
{
988925
$lenA = \strlen($a);
989926
$lenB = \strlen($b);

src/Storage/Device/Wasabi.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ class Wasabi extends S3
4141
*/
4242
public function __construct(string $root, string $accessKey, string $secretKey, string $bucket, string $region = self::EU_CENTRAL_1, string $acl = self::ACL_PRIVATE)
4343
{
44-
parent::__construct($root, $accessKey, $secretKey, $bucket, $region, $acl);
45-
$this->headers['host'] = $bucket.'.'.'s3'.'.'.$region.'.'.'wasabisys'.'.'.'com';
44+
$host = $bucket.'.'.'s3'.'.'.$region.'.'.'wasabisys'.'.'.'com';
45+
parent::__construct($root, $accessKey, $secretKey, $host, $region, $acl);
4646
}
4747

4848
/**

src/Storage/Storage.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ class Storage
1313

1414
const DEVICE_S3 = 's3';
1515

16+
const DEVICE_AWS_S3 = 'awss3';
17+
1618
const DEVICE_DO_SPACES = 'dospaces';
1719

1820
const DEVICE_WASABI = 'wasabi';

0 commit comments

Comments
 (0)