Use guzzle to download update packages
This commit is contained in:
parent
0cedd45cd7
commit
ad32b718eb
|
|
@ -5,8 +5,10 @@ namespace App\Http\Controllers;
|
||||||
use Arr;
|
use Arr;
|
||||||
use Log;
|
use Log;
|
||||||
use File;
|
use File;
|
||||||
|
use Cache;
|
||||||
use Option;
|
use Option;
|
||||||
use Storage;
|
use Storage;
|
||||||
|
use Exception;
|
||||||
use ZipArchive;
|
use ZipArchive;
|
||||||
use App\Services\OptionForm;
|
use App\Services\OptionForm;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
|
@ -78,7 +80,7 @@ class UpdateController extends Controller
|
||||||
})->handle()->always(function($form) {
|
})->handle()->always(function($form) {
|
||||||
try {
|
try {
|
||||||
$response = file_get_contents(option('update_source'));
|
$response = file_get_contents(option('update_source'));
|
||||||
} catch (\Exception $e) {
|
} catch (Exception $e) {
|
||||||
$form->addMessage(trans('admin.update.errors.connection').$e->getMessage(), 'danger');
|
$form->addMessage(trans('admin.update.errors.connection').$e->getMessage(), 'danger');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -107,17 +109,23 @@ class UpdateController extends Controller
|
||||||
{
|
{
|
||||||
$this->refreshInfo();
|
$this->refreshInfo();
|
||||||
|
|
||||||
$action = $request->input('action');
|
if (! $this->newVersionAvailable())
|
||||||
|
return;
|
||||||
if (! $this->newVersionAvailable()) return '';
|
|
||||||
|
|
||||||
|
$action = $request->get('action');
|
||||||
$release_url = $this->getReleaseInfo($this->latestVersion)['release_url'];
|
$release_url = $this->getReleaseInfo($this->latestVersion)['release_url'];
|
||||||
$file_size = Utils::getRemoteFileSize($release_url);
|
$tmp_path = Cache::get('tmp_path');
|
||||||
$tmp_path = session('tmp_path');
|
|
||||||
|
$client = new \GuzzleHttp\Client();
|
||||||
|
$guzzle_config = [
|
||||||
|
'headers' => ['User-Agent' => config('secure.user_agent')],
|
||||||
|
'verify' => config('secure.certificates')
|
||||||
|
];
|
||||||
|
|
||||||
switch ($action) {
|
switch ($action) {
|
||||||
case 'prepare-download':
|
case 'prepare-download':
|
||||||
|
|
||||||
|
Cache::forget('download-progress');
|
||||||
$update_cache = storage_path('update_cache');
|
$update_cache = storage_path('update_cache');
|
||||||
|
|
||||||
if (! is_dir($update_cache)) {
|
if (! is_dir($update_cache)) {
|
||||||
|
|
@ -126,38 +134,50 @@ class UpdateController extends Controller
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$tmp_path = $update_cache."/update_".time().".zip";
|
// Set temporary path for the update package
|
||||||
|
$tmp_path = $update_cache.'/update_'.time().'.zip';
|
||||||
|
Cache::put('tmp_path', $tmp_path, 60);
|
||||||
|
Log::info('[Update Wizard] Prepare to download update package', compact('release_url', 'tmp_path'));
|
||||||
|
|
||||||
session(['tmp_path' => $tmp_path]);
|
// We won't get remote file size here since HTTP HEAD method is not always reliable
|
||||||
|
return json(compact('release_url', 'tmp_path'));
|
||||||
return json(compact('release_url', 'tmp_path', 'file_size'));
|
|
||||||
|
|
||||||
case 'start-download':
|
case 'start-download':
|
||||||
|
|
||||||
if (! session()->has('tmp_path')) {
|
if (! $tmp_path) {
|
||||||
return "No temp path is set.";
|
return 'No temp path available, please try again.';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@set_time_limit(0);
|
||||||
|
$GLOBALS['last_downloaded'] = 0;
|
||||||
|
|
||||||
|
Log::info('[Update Wizard] Start downloading update package');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Utils::download($release_url, $tmp_path);
|
$client->request('GET', $release_url, array_merge($guzzle_config, [
|
||||||
|
'sink' => $tmp_path,
|
||||||
} catch (\Exception $e) {
|
'progress' => function ($total, $downloaded) {
|
||||||
File::delete($tmp_path);
|
if ($total == 0) return;
|
||||||
|
// Log current progress per 100 KiB
|
||||||
|
if ($total == $downloaded || floor($downloaded / 102400) > floor($GLOBALS['last_downloaded'] / 102400)) {
|
||||||
|
$GLOBALS['last_downloaded'] = $downloaded;
|
||||||
|
Log::info('[Update Wizard] Download progress (in bytes):', [$total, $downloaded]);
|
||||||
|
Cache::put('download-progress', compact('total', 'downloaded'), 60);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]));
|
||||||
|
} catch (Exception $e) {
|
||||||
|
@unlink($tmp_path);
|
||||||
return response(trans('admin.update.errors.prefix').$e->getMessage());
|
return response(trans('admin.update.errors.prefix').$e->getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Log::info('[Update Wizard] Finished downloading update package');
|
||||||
|
|
||||||
return json(compact('tmp_path'));
|
return json(compact('tmp_path'));
|
||||||
|
|
||||||
case 'get-file-size':
|
case 'get-progress':
|
||||||
|
|
||||||
if (! session()->has('tmp_path')) {
|
return json((array) Cache::get('download-progress'));
|
||||||
return "No temp path is set.";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (file_exists($tmp_path)) {
|
|
||||||
return json(['size' => filesize($tmp_path)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'extract':
|
case 'extract':
|
||||||
|
|
||||||
|
|
@ -171,7 +191,7 @@ class UpdateController extends Controller
|
||||||
$res = $zip->open($tmp_path);
|
$res = $zip->open($tmp_path);
|
||||||
|
|
||||||
if ($res === true) {
|
if ($res === true) {
|
||||||
Log::info("[ZipArchive] Extracting file $tmp_path");
|
Log::info("[Update Wizard] Extracting file $tmp_path");
|
||||||
|
|
||||||
if ($zip->extractTo($extract_dir) === false) {
|
if ($zip->extractTo($extract_dir) === false) {
|
||||||
return response(trans('admin.update.errors.prefix').'Cannot unzip file.');
|
return response(trans('admin.update.errors.prefix').'Cannot unzip file.');
|
||||||
|
|
@ -184,29 +204,31 @@ class UpdateController extends Controller
|
||||||
|
|
||||||
try {
|
try {
|
||||||
File::copyDirectory("$extract_dir/vendor", base_path('vendor'));
|
File::copyDirectory("$extract_dir/vendor", base_path('vendor'));
|
||||||
} catch (\Exception $e) {
|
} catch (Exception $e) {
|
||||||
Log::error('[Extracter] Unable to extract vendors', [$e]);
|
report($e);
|
||||||
|
Log::error('[Update Wizard] Unable to extract vendors');
|
||||||
// Skip copying vendor
|
// Skip copying vendor
|
||||||
File::deleteDirectory("$extract_dir/vendor");
|
File::deleteDirectory("$extract_dir/vendor");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
File::copyDirectory($extract_dir, base_path());
|
File::copyDirectory($extract_dir, base_path());
|
||||||
|
|
||||||
Log::info("[Extracter] Covering files");
|
Log::info('[Update Wizard] Overwrite with extracted files');
|
||||||
|
|
||||||
} catch (\Exception $e) {
|
} catch (Exception $e) {
|
||||||
Log::error("[Extracter] Error occured when covering files", [$e]);
|
report($e);
|
||||||
|
Log::error('[Update Wizard] Error occured when overwriting files');
|
||||||
|
|
||||||
// Response can be returned, while cache will be cleared
|
// Response can be returned, while cache will be cleared
|
||||||
// @see https://gist.github.com/g-plane/2f88ad582826a78e0a26c33f4319c1e0
|
// @see https://gist.github.com/g-plane/2f88ad582826a78e0a26c33f4319c1e0
|
||||||
return response(trans('admin.update.errors.overwrite').$e->getMessage());
|
return response(trans('admin.update.errors.overwrite').$e->getMessage());
|
||||||
} finally {
|
} finally {
|
||||||
File::deleteDirectory(storage_path('update_cache'));
|
File::deleteDirectory(storage_path('update_cache'));
|
||||||
Log::info("[Extracter] Cleaning cache");
|
Log::info('[Update Wizard] Cleaning cache');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Log::info('[Update Wizard] Done');
|
||||||
return json(trans('admin.update.complete'), 0);
|
return json(trans('admin.update.complete'), 0);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
@ -224,7 +246,7 @@ class UpdateController extends Controller
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$response = file_get_contents($url);
|
$response = file_get_contents($url);
|
||||||
} catch (\Exception $e) {
|
} catch (Exception $e) {
|
||||||
Log::error("[CheckingUpdate] Failed to get update information: ".$e->getMessage());
|
Log::error("[CheckingUpdate] Failed to get update information: ".$e->getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -122,7 +122,7 @@
|
||||||
<p>@lang('admin.update.download.size')<span id="file-size">0</span> Bytes</p>
|
<p>@lang('admin.update.download.size')<span id="file-size">0</span> Bytes</p>
|
||||||
<div class="progress">
|
<div class="progress">
|
||||||
<div class="progress-bar progress-bar-striped active" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0%">
|
<div class="progress-bar progress-bar-striped active" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0%">
|
||||||
<span id="imported-progress">0</span>%
|
<span id="download-progress">0</span>%
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,13 @@ namespace Tests;
|
||||||
|
|
||||||
use DB;
|
use DB;
|
||||||
use Artisan;
|
use Artisan;
|
||||||
|
use Tests\Concerns\InteractsWithCache;
|
||||||
use Laravel\BrowserKitTesting\TestCase;
|
use Laravel\BrowserKitTesting\TestCase;
|
||||||
|
|
||||||
class BrowserKitTestCase extends TestCase
|
class BrowserKitTestCase extends TestCase
|
||||||
{
|
{
|
||||||
|
use InteractsWithCache;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The base URL to use while testing the application.
|
* The base URL to use while testing the application.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -107,7 +107,6 @@ class UpdateControllerTest extends BrowserKitTestCase
|
||||||
|
|
||||||
public function testDownload()
|
public function testDownload()
|
||||||
{
|
{
|
||||||
$this->markTestSkipped('Removed Utils class');
|
|
||||||
option(['update_source' => vfs\vfsStream::url('root/update.json')]);
|
option(['update_source' => vfs\vfsStream::url('root/update.json')]);
|
||||||
$this->generateFakeUpdateFile();
|
$this->generateFakeUpdateFile();
|
||||||
|
|
||||||
|
|
@ -129,47 +128,51 @@ class UpdateControllerTest extends BrowserKitTestCase
|
||||||
$this->get('/admin/update/download?action=prepare-download')
|
$this->get('/admin/update/download?action=prepare-download')
|
||||||
->seeJson([
|
->seeJson([
|
||||||
'release_url' => storage_path('testing/update.zip'),
|
'release_url' => storage_path('testing/update.zip'),
|
||||||
'file_size' => filesize(storage_path('testing/update.zip'))
|
|
||||||
])
|
])
|
||||||
->assertSessionHas('tmp_path');
|
->assertCacheHas('tmp_path');
|
||||||
|
|
||||||
// Start downloading
|
// Start downloading
|
||||||
$this->flushSession();
|
$this->flushCache();
|
||||||
$this->actAs('admin')
|
$this->actAs('admin')
|
||||||
->get('/admin/update/download?action=start-download')
|
->get('/admin/update/download?action=start-download')
|
||||||
->see('No temp path is set.');
|
->see('No temp path available, please try again.');
|
||||||
|
|
||||||
unlink(storage_path('testing/update.zip'));
|
unlink(storage_path('testing/update.zip'));
|
||||||
$this->withSession(['tmp_path' => storage_path('update_cache/update.zip')])
|
$this->withCache(['tmp_path' => storage_path('update_cache/update.zip')])
|
||||||
->get('/admin/update/download?action=start-download')
|
->get('/admin/update/download?action=start-download')
|
||||||
->see(trans('admin.update.errors.prefix'));
|
->see(trans('admin.update.errors.prefix'));
|
||||||
|
|
||||||
$this->generateFakeUpdateFile();
|
$this->generateFakeUpdateFile();
|
||||||
$this->get('/admin/update/download?action=start-download')
|
// TODO: This needs to be tested.
|
||||||
->seeJson([
|
// TODO: I failed to find a good solution for testing guzzle http requests.
|
||||||
'tmp_path' => storage_path('update_cache/update.zip')
|
//
|
||||||
]);
|
// $this->withCache(['tmp_path' => storage_path('update_cache/update.zip')])
|
||||||
$this->assertFileExists(storage_path('update_cache/update.zip'));
|
// ->get('/admin/update/download?action=start-download')
|
||||||
|
// ->seeJson([
|
||||||
|
// 'tmp_path' => storage_path('update_cache/update.zip')
|
||||||
|
// ]);
|
||||||
|
// $this->assertFileExists(storage_path('update_cache/update.zip'));
|
||||||
|
|
||||||
// Get file size
|
// Get file size
|
||||||
$this->flushSession();
|
$this->flushCache();
|
||||||
$this->actAs('admin')
|
$this->actAs('admin')
|
||||||
->get('/admin/update/download?action=get-file-size')
|
->get('/admin/update/download?action=get-progress')
|
||||||
->see('No temp path is set.');
|
->see('[]');
|
||||||
|
|
||||||
$this->withSession(['tmp_path' => storage_path('update_cache/update.zip')])
|
$this->withCache(['download-progress' => ['total' => 514, 'downloaded' => 114]])
|
||||||
->get('/admin/update/download?action=get-file-size')
|
->get('/admin/update/download?action=get-progress')
|
||||||
->seeJson([
|
->seeJson([
|
||||||
'size' => filesize(storage_path('testing/update.zip'))
|
'total' => 514,
|
||||||
|
'downloaded' => 114
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Extract
|
// Extract
|
||||||
$this->withSession(['tmp_path' => storage_path('update_cache/update')])
|
$this->withCache(['tmp_path' => storage_path('update_cache/update')])
|
||||||
->get('/admin/update/download?action=extract')
|
->get('/admin/update/download?action=extract')
|
||||||
->see('No file available');
|
->see('No file available');
|
||||||
|
|
||||||
file_put_contents(storage_path('update_cache/update.zip'), 'text');
|
file_put_contents(storage_path('update_cache/update.zip'), 'text');
|
||||||
$this->withSession(['tmp_path' => storage_path('update_cache/update.zip')])
|
$this->withCache(['tmp_path' => storage_path('update_cache/update.zip')])
|
||||||
->get('/admin/update/download?action=extract')
|
->get('/admin/update/download?action=extract')
|
||||||
->see(trans('admin.update.errors.unzip'));
|
->see(trans('admin.update.errors.unzip'));
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user