Refactor Self Update Endpoints and Add Update Console Command

This commit is contained in:
gohil jayvirsinh
2020-05-17 07:04:43 +00:00
committed by Mohit Panjwani
parent a24d8d3ebc
commit 183953f4c4
5 changed files with 362 additions and 97 deletions

View File

@ -0,0 +1,189 @@
<?php
namespace Crater\Console\Commands;
use Illuminate\Console\Command;
use Crater\Space\Updater;
use Crater\Setting;
class UpdateCommand extends Command
{
public $installed;
public $version;
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'crater:update';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Automatically update your crater app';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*/
public function handle()
{
set_time_limit(3600); // 1 hour
$this->installed = $this->getInstalledVersion();
$this->version = $this->getLatestVersion();
if (!$this->version) {
$this->info('No Update Available! You are already on the latest version.');
return;
}
if (!$this->confirm("Do you wish to update to {$this->version}?")) {
return;
}
if (!$path = $this->download()) {
return;
}
if (!$path = $this->unzip($path)) {
return;
}
if (!$this->copyFiles($path)) {
return;
}
if (!$this->migrateUpdate()) {
return;
}
if (!$this->finish()) {
return;
}
$this->info('Successfully updated to ' . $this->version);
}
public function getInstalledVersion()
{
return Setting::getSetting('version');
}
public function getLatestVersion()
{
$this->info('Your currently installed version is ' . $this->installed);
$this->line('');
$this->info('Checking for update...');
try {
$response = Updater::checkForUpdate($this->installed);
if ($response->success) {
return $response->version->version;
}
return false;
} catch (\Exception $e) {
$this->error($e->getMessage());
return false;
}
}
public function download()
{
$this->info('Downloading update...');
try {
$path = Updater::download($this->version);
if (!is_string($path)) {
$this->error('Download exception');
return false;
}
} catch (\Exception $e) {
$this->error($e->getMessage());
return false;
}
return $path;
}
public function unzip($path)
{
$this->info('Unzipping update package...');
try {
$path = Updater::unzip($path);
if (!is_string($path)) {
$this->error('Unzipping exception');
return false;
}
} catch (\Exception $e) {
$this->error($e->getMessage());
return false;
}
return $path;
}
public function copyFiles($path)
{
$this->info('Copying update files...');
try {
Updater::copyFiles($path);
} catch (\Exception $e) {
$this->error($e->getMessage());
return false;
}
return true;
}
public function migrateUpdate()
{
$this->info('Running Migrations...');
try {
Updater::migrateUpdate();
} catch (\Exception $e) {
$this->error($e->getMessage());
return false;
}
return true;
}
public function finish()
{
$this->info('Finishing update...');
try {
Updater::finishUpdate($this->installed, $this->version);
} catch (\Exception $e) {
$this->error($e->getMessage());
return false;
}
return true;
}
}

View File

@ -12,7 +12,8 @@ class Kernel extends ConsoleKernel
* @var array
*/
protected $commands = [
Commands\ResetApp::class
Commands\ResetApp::class,
Commands\UpdateCommand::class
];
/**

View File

@ -2,23 +2,81 @@
namespace Crater\Http\Controllers;
use Crater\Setting;
use Illuminate\Http\Request;
use Crater\Space\Updater;
use Crater\Space\SiteApi;
use Illuminate\Support\Facades\Artisan;
class UpdateController extends Controller
{
public function update(Request $request)
public function download(Request $request)
{
set_time_limit(600); // 10 minutes
$request->validate([
'version' => 'required',
]);
$json = Updater::update($request->installed, $request->version);
$path = Updater::download($request->version);
return response()->json($json);
return response()->json([
'success' => true,
'path' => $path
]);
}
public function unzip(Request $request)
{
$request->validate([
'path' => 'required',
]);
try {
$path = Updater::unzip($request->path);
return response()->json([
'success' => true,
'path' => $path
]);
} catch (\Exception $e) {
return response()->json([
'success' => false,
'error' => $e->getMessage()
]);
}
}
public function copyFiles(Request $request)
{
$request->validate([
'path' => 'required',
]);
$path = Updater::copyFiles($request->path);
return response()->json([
'success' => true,
'path' => $path
]);
}
public function migrate(Request $request)
{
Updater::migrateUpdate();
return response()->json([
'success' => true
]);
}
public function finishUpdate(Request $request)
{
$request->validate([
'installed' => 'required',
'version' => 'required',
]);
$json = Updater::finishUpdate($request->installed, $request->version);
return response()->json($json);
@ -28,7 +86,7 @@ class UpdateController extends Controller
{
set_time_limit(600); // 10 minutes
$json = Updater::checkForUpdate();
$json = Updater::checkForUpdate(Setting::getSetting('version'));
return response()->json($json);
}

View File

@ -2,28 +2,43 @@
namespace Crater\Space;
use File;
use ZipArchive;
use Artisan;
use GuzzleHttp\Exception\RequestException;
use Crater\Space\SiteApi;
use Crater\Events\UpdateFinished;
use Crater\Setting;
use Illuminate\Http\Request;
use ZipArchive;
class Updater
{
use SiteApi;
public static function update($installed, $version)
public static function checkForUpdate($installed_version)
{
$data = null;
if(env('APP_ENV') === 'development')
{
$url = 'https://craterapp.com/downloads/check/latest/'. $installed_version . '?type=update&is_dev=1';
} else {
$url = 'https://craterapp.com/downloads/check/latest/'. $installed_version . '?type=update';
}
$response = static::getRemote($url, ['timeout' => 100, 'track_redirects' => true]);
if ($response && ($response->getStatusCode() == 200)) {
$data = $response->getBody()->getContents();
}
return json_decode($data);
}
public static function download($new_version)
{
$data = null;
$path = null;
if(env('APP_ENV') === 'development')
{
$url = 'https://craterapp.com/downloads/file/'.$version.'?type=update&is_dev=1';
if (env('APP_ENV') === 'development') {
$url = 'https://craterapp.com/downloads/file/' . $new_version . '?type=update&is_dev=1';
} else {
$url = 'https://craterapp.com/downloads/file/'.$version.'?type=update';
$url = 'https://craterapp.com/downloads/file/' . $new_version . '?type=update';
}
$response = static::getRemote($url, ['timeout' => 100, 'track_redirects' => true]);
@ -44,66 +59,68 @@ class Updater
}
// Create temp directory
$path = 'temp-' . md5(mt_rand());
$path2 = 'temp2-' . md5(mt_rand());
$temp_path = storage_path('app') . '/' . $path;
$temp_path2 = storage_path('app') . '/' . $path2;
$temp_dir = storage_path('app/temp-' . md5(mt_rand()));
if (!File::isDirectory($temp_path)) {
File::makeDirectory($temp_path);
File::makeDirectory($temp_path2);
if (!File::isDirectory($temp_dir)) {
File::makeDirectory($temp_dir);
}
try {
$file = $temp_path . '/upload.zip';
$zip_file_path = $temp_dir . '/upload.zip';
// Add content to the Zip file
$uploaded = is_int(file_put_contents($file, $data)) ? true : false;
$uploaded = is_int(file_put_contents($zip_file_path, $data)) ? true : false;
if (!$uploaded) {
return false;
}
return $zip_file_path;
}
public static function unzip($zip_file_path)
{
if(!file_exists($zip_file_path)) {
throw new \Exception('Zip file not found');
}
$temp_extract_dir = storage_path('app/temp2-' . md5(mt_rand()));
if (!File::isDirectory($temp_extract_dir)) {
File::makeDirectory($temp_extract_dir);
}
// Unzip the file
$zip = new ZipArchive();
if ($zip->open($file)) {
$zip->extractTo($temp_path2);
if ($zip->open($zip_file_path)) {
$zip->extractTo($temp_extract_dir);
}
$zip->close();
// Delete zip file
File::delete($file);
File::delete($zip_file_path);
if (!File::copyDirectory($temp_path2.'/Crater', base_path())) {
return $temp_extract_dir;
}
public static function copyFiles($temp_extract_dir)
{
if (!File::copyDirectory($temp_extract_dir . '/Crater', base_path())) {
return false;
}
// Delete temp directory
File::deleteDirectory($temp_path);
File::deleteDirectory($temp_path2);
File::deleteDirectory($temp_extract_dir);
return [
'success' => true,
'error' => false,
'data' => []
];
} catch (\Exception $e) {
if (File::isDirectory($temp_path)) {
// Delete temp directory
File::deleteDirectory($temp_path);
File::deleteDirectory($temp_path2);
return true;
}
return [
'success' => false,
'error' => 'Update error',
'data' => []
];
}
public static function migrateUpdate()
{
Artisan::call('migrate --force');
return true;
}
public static function finishUpdate($installed, $version)
@ -117,22 +134,4 @@ class Updater
];
}
public static function checkForUpdate()
{
$data = null;
if(env('APP_ENV') === 'development')
{
$url = 'https://craterapp.com/downloads/check/latest/'. Setting::getSetting('version') . '?type=update&is_dev=1';
} else {
$url = 'https://craterapp.com/downloads/check/latest/'. Setting::getSetting('version') . '?type=update';
}
$response = static::getRemote($url, ['timeout' => 100, 'track_redirects' => true]);
if ($response && ($response->getStatusCode() == 200)) {
$data = $response->getBody()->getContents();
}
return json_decode($data);
}
}

View File

@ -122,23 +122,41 @@ Route::group(['middleware' => 'api'], function () {
'middleware' => 'admin'
], function () {
// Auto update routes
// Self Update
//----------------------------------
Route::post('/update', [
'as' => 'auto.update',
'uses' => 'UpdateController@update'
Route::get('/check/update', [
'as' => 'update.check',
'uses' => 'UpdateController@checkLatestVersion'
]);
Route::post('/update/download', [
'as' => 'update.download',
'uses' => 'UpdateController@download'
]);
Route::post('/update/unzip', [
'as' => 'update.unzip',
'uses' => 'UpdateController@unzip'
]);
Route::post('/update/copy', [
'as' => 'update.copy',
'uses' => 'UpdateController@copyFiles'
]);
Route::post('/update/migrate', [
'as' => 'update.migrate',
'uses' => 'UpdateController@migrate'
]);
Route::post('/update/finish', [
'as' => 'auto.update.finish',
'as' => 'update.finish',
'uses' => 'UpdateController@finishUpdate'
]);
Route::get('/check/update', [
'as' => 'check.update',
'uses' => 'UpdateController@checkLatestVersion'
]);
// Bootstrap
//----------------------------------
Route::get('/bootstrap', [
'as' => 'bootstrap',