Skip to content

Commit b774622

Browse files
committed
Add base support for AWS/Wings backup adapters
1 parent 1946883 commit b774622

File tree

9 files changed

+447
-15
lines changed

9 files changed

+447
-15
lines changed
Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
<?php
2+
3+
namespace Pterodactyl\Extensions\Backups;
4+
5+
use Closure;
6+
use Illuminate\Support\Arr;
7+
use Illuminate\Support\Str;
8+
use Webmozart\Assert\Assert;
9+
use InvalidArgumentException;
10+
use Aws\S3\S3MultiRegionClient;
11+
use League\Flysystem\AdapterInterface;
12+
use League\Flysystem\AwsS3v3\AwsS3Adapter;
13+
use League\Flysystem\Memory\MemoryAdapter;
14+
use Illuminate\Contracts\Config\Repository;
15+
16+
class BackupManager
17+
{
18+
/**
19+
* @var \Illuminate\Foundation\Application
20+
*/
21+
protected $app;
22+
23+
/**
24+
* @var \Illuminate\Contracts\Config\Repository
25+
*/
26+
protected $config;
27+
28+
/**
29+
* The array of resolved backup drivers.
30+
*
31+
* @var \League\Flysystem\AdapterInterface[]
32+
*/
33+
protected $adapters = [];
34+
35+
/**
36+
* The registered custom driver creators.
37+
*
38+
* @var array
39+
*/
40+
protected $customCreators;
41+
42+
/**
43+
* BackupManager constructor.
44+
*
45+
* @param \Illuminate\Foundation\Application $app
46+
*/
47+
public function __construct($app)
48+
{
49+
$this->app = $app;
50+
$this->config = $app->make(Repository::class);
51+
}
52+
53+
/**
54+
* Returns a backup adapter instance.
55+
*
56+
* @param string|null $name
57+
* @return \League\Flysystem\AdapterInterface
58+
*/
59+
public function adapter(string $name = null)
60+
{
61+
return $this->get($name ?: $this->getDefaultAdapter());
62+
}
63+
64+
/**
65+
* Set the given backup adapter instance.
66+
*
67+
* @param string $name
68+
* @param \League\Flysystem\AdapterInterface $disk
69+
* @return $this
70+
*/
71+
public function set(string $name, $disk)
72+
{
73+
$this->adapters[$name] = $disk;
74+
75+
return $this;
76+
}
77+
78+
/**
79+
* Gets a backup adapter.
80+
*
81+
* @param string $name
82+
* @return \League\Flysystem\AdapterInterface
83+
*/
84+
protected function get(string $name)
85+
{
86+
return $this->adapters[$name] = $this->resolve($name);
87+
}
88+
89+
/**
90+
* Resolve the given backup disk.
91+
*
92+
* @param string $name
93+
* @return \League\Flysystem\AdapterInterface
94+
*/
95+
protected function resolve(string $name)
96+
{
97+
$config = $this->getConfig($name);
98+
99+
if (empty($config['adapter'])) {
100+
throw new InvalidArgumentException(
101+
"Backup disk [{$name}] does not have a configured adapter."
102+
);
103+
}
104+
105+
$adapter = $config['adapter'];
106+
107+
if (isset($this->customCreators[$name])) {
108+
return $this->callCustomCreator($config);
109+
}
110+
111+
$adapterMethod = 'create' . Str::studly($adapter) . 'Adapter';
112+
if (method_exists($this, $adapterMethod)) {
113+
$instance = $this->{$adapterMethod}($config);
114+
115+
Assert::isInstanceOf($instance, AdapterInterface::class);
116+
117+
return $instance;
118+
}
119+
120+
throw new InvalidArgumentException("Adapter [{$adapter}] is not supported.");
121+
}
122+
123+
/**
124+
* Calls a custom creator for a given adapter type.
125+
*
126+
* @param array $config
127+
* @return \League\Flysystem\AdapterInterface
128+
*/
129+
protected function callCustomCreator(array $config)
130+
{
131+
$adapter = $this->customCreators[$config['adapter']]($this->app, $config);
132+
133+
Assert::isInstanceOf($adapter, AdapterInterface::class);
134+
135+
return $adapter;
136+
}
137+
138+
/**
139+
* Creates a new wings adapter.
140+
*
141+
* @param array $config
142+
* @return \League\Flysystem\AdapterInterface
143+
*/
144+
public function createWingsAdapter(array $config)
145+
{
146+
return new MemoryAdapter(null);
147+
}
148+
149+
/**
150+
* Creates a new S3 adapter.
151+
*
152+
* @param array $config
153+
* @return \League\Flysystem\AdapterInterface
154+
*/
155+
public function createS3Adapter(array $config)
156+
{
157+
$config['version'] = 'latest';
158+
159+
if (! empty($config['key']) && ! empty($config['secret'])) {
160+
$config['credentials'] = Arr::only($config, ['key', 'secret', 'token']);
161+
}
162+
163+
$client = new S3MultiRegionClient($config);
164+
165+
return new AwsS3Adapter($client, $config['bucket'], $config['prefix'] ?? '', $config['options'] ?? []);
166+
}
167+
168+
/**
169+
* Returns the configuration associated with a given backup type.
170+
*
171+
* @param string $name
172+
* @return array
173+
*/
174+
protected function getConfig(string $name)
175+
{
176+
return $this->config->get("backups.disks.{$name}") ?: [];
177+
}
178+
179+
/**
180+
* Get the default backup driver name.
181+
*
182+
* @return string
183+
*/
184+
public function getDefaultAdapter()
185+
{
186+
return $this->config->get('backups.default');
187+
}
188+
189+
/**
190+
* Set the default session driver name.
191+
*
192+
* @param string $name
193+
*/
194+
public function setDefaultAdapter(string $name)
195+
{
196+
$this->config->set('backups.default', $name);
197+
}
198+
199+
/**
200+
* Unset the given adapter instances.
201+
*
202+
* @param string|string[] $adapter
203+
* @return $this
204+
*/
205+
public function forget($adapter)
206+
{
207+
foreach ((array) $adapter as $adapterName) {
208+
unset($this->adapters[$adapter]);
209+
}
210+
211+
return $this;
212+
}
213+
214+
/**
215+
* Register a custom adapter creator closure.
216+
*
217+
* @param string $adapter
218+
* @param \Closure $callback
219+
* @return $this
220+
*/
221+
public function extend(string $adapter, Closure $callback)
222+
{
223+
$this->customCreators[$adapter] = $callback;
224+
225+
return $this;
226+
}
227+
}

app/Models/Backup.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ class Backup extends Model
2626

2727
const RESOURCE_NAME = 'backup';
2828

29-
const DISK_LOCAL = 'local';
30-
const DISK_AWS_S3 = 's3';
29+
const ADAPTER_WINGS = 'wings';
30+
const ADAPTER_AWS_S3 = 's3';
3131

3232
/**
3333
* @var string
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
namespace Pterodactyl\Providers;
4+
5+
use Illuminate\Support\ServiceProvider;
6+
use Pterodactyl\Extensions\Backups\BackupManager;
7+
use Illuminate\Contracts\Support\DeferrableProvider;
8+
9+
class BackupsServiceProvider extends ServiceProvider implements DeferrableProvider
10+
{
11+
/**
12+
* Register the S3 backup disk.
13+
*/
14+
public function register()
15+
{
16+
$this->app->singleton(BackupManager::class, function ($app) {
17+
return new BackupManager($app);
18+
});
19+
}
20+
21+
/**
22+
* @return string[]
23+
*/
24+
public function provides()
25+
{
26+
return [BackupManager::class];
27+
}
28+
}

app/Repositories/Wings/DaemonBackupRepository.php

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,25 +11,48 @@
1111

1212
class DaemonBackupRepository extends DaemonRepository
1313
{
14+
/**
15+
* @var string|null
16+
*/
17+
protected $adapter;
18+
19+
/**
20+
* Sets the backup adapter for this execution instance.
21+
*
22+
* @param string $adapter
23+
* @return $this
24+
*/
25+
public function setBackupAdapter(string $adapter)
26+
{
27+
$this->adapter = $adapter;
28+
29+
return $this;
30+
}
31+
1432
/**
1533
* Tells the remote Daemon to begin generating a backup for the server.
1634
*
1735
* @param \Pterodactyl\Models\Backup $backup
36+
* @param string|null $presignedUrl
1837
* @return \Psr\Http\Message\ResponseInterface
1938
*
2039
* @throws \Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException
2140
*/
22-
public function backup(Backup $backup): ResponseInterface
41+
public function backup(Backup $backup, string $presignedUrl = null): ResponseInterface
2342
{
2443
Assert::isInstanceOf($this->server, Server::class);
2544

45+
$this->app->make('config')->get();
46+
2647
try {
2748
return $this->getHttpClient()->post(
2849
sprintf('/api/servers/%s/backup', $this->server->uuid),
2950
[
3051
'json' => [
52+
'adapter' => $this->adapter ?? config('backups.default'),
3153
'uuid' => $backup->uuid,
3254
'ignored_files' => $backup->ignored_files,
55+
'presigned_url' => $presignedUrl,
3356
],
3457
]
3558
);

0 commit comments

Comments
 (0)