diff --git a/app/Http/Controllers/SetupController.php b/app/Http/Controllers/SetupController.php index 09bbbbd3..d6a266df 100644 --- a/app/Http/Controllers/SetupController.php +++ b/app/Http/Controllers/SetupController.php @@ -50,7 +50,7 @@ class SetupController extends Controller // skip if the file is not valid or expired if (!isset($matches[2]) || - version_compare($matches[2], option('version'), '<')) { + version_compare($matches[2], config('app.version'), '<')) { continue; } diff --git a/app/Http/Controllers/UpdateController.php b/app/Http/Controllers/UpdateController.php new file mode 100644 index 00000000..833a855b --- /dev/null +++ b/app/Http/Controllers/UpdateController.php @@ -0,0 +1,184 @@ +updateSource = option('update_source'); + + $this->currentVersion = config('app.version'); + } + + public function showUpdatePage() + { + $info = [ + 'latest_version' => '', + 'current_version' => $this->currentVersion, + 'release_note' => '', + 'release_url' => '', + 'pre_release' => false, + // fallback to current time + 'release_time' => time(), + 'new_version_available' => false + ]; + + // if current update source is available + if ($this->getUpdateInfo()) { + $info['latest_version'] = $this->getUpdateInfo('latest_version'); + + if ($current_release = $this->getReleaseInfo($this->currentVersion)) { + $info['release_time'] = Arr::get($current_release, 'release_time') ?: time(); + } + + $info['new_version_available'] = version_compare( + $info['latest_version'], + $info['current_version'], '>' + ); + + if ($detail = $this->getReleaseInfo($info['latest_version'])) { + $info = array_merge($info, Arr::only($detail, [ + 'release_note', + 'release_url', + 'release_time', + 'pre_release' + ])); + } else { + // if detailed release info is not given + $info['new_version_available'] = false; + } + } + + + return view('admin.update')->with('info', $info); + } + + public function checkUpdates() + { + return json([ + 'latest' => $this->getUpdateInfo('latest_version'), + 'available' => $this->newVersionAvailable() + ]); + } + + protected function newVersionAvailable() + { + $latest = $this->getUpdateInfo('latest_version'); + + return version_compare($latest, $this->currentVersion, '>') && $this->getReleaseInfo($latest); + } + + public function download(Request $request) + { + $action = $request->input('action'); + + if (!$this->newVersionAvailable()) return; + + $release_url = $this->getReleaseInfo($this->latestVersion)['release_url']; + $file_size = Utils::getRemoteFileSize($release_url); + $tmp_path = session('tmp_path'); + + switch ($action) { + case 'prepare-download': + + $update_cache = storage_path('update_cache'); + + if (!is_dir($update_cache)) { + if (false === mkdir($update_cache)) { + exit('创建下载缓存文件夹失败,请检查目录权限。'); + } + } + + $tmp_path = $update_cache."/update_".time().".zip"; + + session(['tmp_path' => $tmp_path]); + + return json(compact('release_url', 'tmp_path', 'file_size')); + + break; + + case 'start-download': + + if (!session()->has('tmp_path')) return "No temp path is set."; + + try { + Utils::download($release_url, $tmp_path); + + } catch (\Exception $e) { + Storage::remove($tmp_path); + + exit('发生错误:'.$e->getMessage()); + } + + return json(compact('tmp_path')); + + break; + + case 'get-file-size': + + if (!session()->has('tmp_path')) return "No temp path is set."; + + if (file_exists($tmp_path)) { + return json(['size' => filesize($tmp_path)]); + } + + break; + + case 'extract': + // + break; + + default: + # code... + break; + } + } + + protected function getUpdateInfo($key = null) + { + if (!$this->updateInfo) { + // add timestamp to control cdn cache + $url = $this->updateSource."?v=".substr(time(), 0, -3); + + try { + $response = file_get_contents($url); + } catch (\Exception $e) { + Log::error("[CheckingUpdate] Failed to get update information: ".$e->getMessage()); + } + + if (isset($response)) { + $this->updateInfo = json_decode($response, true); + } + + } + + $this->latestVersion = Arr::get($this->updateInfo, 'latest_version', $this->currentVersion); + + if (!is_null($key)) { + return Arr::get($this->updateInfo, $key); + } + + return $this->updateInfo; + } + + protected function getReleaseInfo($version) + { + return Arr::get($this->getUpdateInfo('releases'), $version); + } + +} diff --git a/app/Http/Routes/web.php b/app/Http/Routes/web.php index f6f4e785..cecc1a6c 100644 --- a/app/Http/Routes/web.php +++ b/app/Http/Routes/web.php @@ -102,7 +102,12 @@ Route::group(['middleware' => 'admin', 'prefix' => 'admin'], function () Route::any('/customize', 'AdminController@customize'); Route::any('/score', 'AdminController@score'); Route::any('/options', 'AdminController@options'); - Route::any('/update', 'AdminController@update'); + + Route::any('/update', 'UpdateController@showUpdatePage'); + + Route::any('/update/download', 'UpdateController@download'); + + Route::get('/update/check', 'UpdateController@checkUpdates'); Route::get('/users', 'AdminController@users'); Route::get('/players', 'AdminController@players'); diff --git a/app/Services/Utils.php b/app/Services/Utils.php index a3074f40..e8073119 100644 --- a/app/Services/Utils.php +++ b/app/Services/Utils.php @@ -40,6 +40,64 @@ class Utils } } + public static function download($url, $path) + { + set_time_limit(0); + + touch($path); + + Log::info("[File Downloader] Download started, source: $url"); + Log::info("[File Downloader] ======================================"); + + if ($fp = fopen($url, "rb")) { + + if (!$download_fp = fopen($path, "wb")) { + return false; + } + + while (!feof($fp)) { + + if (!file_exists($path)) { + // cancel downloading if destination is no longer available + fclose($download_fp); + + return false; + } + + Log::info("[Download] 1024 bytes wrote"); + fwrite($download_fp, fread($fp, 1024 * 8 ), 1024 * 8); + } + + fclose($download_fp); + fclose($fp); + + Log::info("[File Downloader] Finished downloading, data stored to: $path"); + Log::info("[File Downloader] ==========================================="); + + return true; + } else { + return false; + } + } + + public static function getRemoteFileSize($url) + { + $regex = '/^Content-Length: *+\K\d++$/im'; + + if (!$fp = @fopen($url, 'rb')) { + return false; + } + + if ( + isset($http_response_header) && + preg_match($regex, implode("\n", $http_response_header), $matches) + ) { + return (int)$matches[0]; + } + + return strlen(stream_get_contents($fp)); + } + /** * Generate random string * diff --git a/config/app.php b/config/app.php index 418502bf..3f95e82e 100644 --- a/config/app.php +++ b/config/app.php @@ -9,7 +9,7 @@ return [ | Version of Blessing Skin Server | */ - 'version' => '3.1.2', + 'version' => '3.2-pr2', /* |-------------------------------------------------------------------------- diff --git a/resources/assets/src/js/admin.js b/resources/assets/src/js/admin.js index 340dea99..99d01b30 100644 --- a/resources/assets/src/js/admin.js +++ b/resources/assets/src/js/admin.js @@ -2,7 +2,7 @@ * @Author: printempw * @Date: 2016-07-22 14:02:44 * @Last Modified by: printempw - * @Last Modified time: 2016-09-24 19:58:24 + * @Last Modified time: 2016-11-25 12:45:28 */ 'use strict'; @@ -309,3 +309,80 @@ function deletePlayer(pid) { error: showAjaxError }); } + +function downloadUpdates() { + var file_size = 0; + var progress = 0; + + console.log("Prepared to download"); + + $.ajax({ + url: './update/download?action=prepare-download', + type: 'GET', + dataType: 'json', + beforeSend: function() { + $('#update-button').html(' 正在准备').prop('disabled', 'disabled'); + }, + }) + .done(function(json) { + console.log(json); + + file_size = json.file_size; + + $('#file-size').html(file_size); + + $('#modal-start-download').modal({ + 'backdrop': 'static', + 'keyboard': false + }); + + console.log("started downloading"); + $.ajax({ + url: './update/download?action=start-download', + type: 'POST', + dataType: 'json' + }) + .done(function(json) { + // set progress to 100 when got the response + progress = 100; + + console.log("Downloading finished"); + console.log(json); + }) + .fail(showAjaxError); + + var interval_id = window.setInterval(function() { + + if (progress == 100) { + clearInterval(interval_id); + + $('#modal-start-download').modal('toggle'); + + swal({ + type: 'success', + html: '下载完成!' + }).then(function(new_name) { + // + }); + } else { + $.ajax({ + url: './update/download?action=get-file-size', + type: 'GET' + }) + .done(function(json) { + progress = (json.size / file_size * 100).toFixed(2); + + $('#imported-progress').html(progress); + $('.progress-bar').css('width', progress+'%').attr('aria-valuenow', progress); + + console.log("Progress: "+progress); + }) + .fail(showAjaxError); + } + + }, 300); + + }) + .fail(showAjaxError); + +} diff --git a/resources/views/admin/master.tpl b/resources/views/admin/master.tpl index 017bacda..3c1337ab 100644 --- a/resources/views/admin/master.tpl +++ b/resources/views/admin/master.tpl @@ -118,10 +118,11 @@ @if (option('check_update') == '1') diff --git a/resources/views/admin/update.tpl b/resources/views/admin/update.tpl index 4275b13b..7f4f92bb 100644 --- a/resources/views/admin/update.tpl +++ b/resources/views/admin/update.tpl @@ -21,7 +21,6 @@ -
@@ -31,41 +30,45 @@

更新信息

- @if ($updater->newVersionAvailable()) + @if ($info['new_version_available'])
有更新可用。
+ @if($info['pre_release']) +
本次更新为预发布版,请谨慎选择是否更新。
+ @endif +
最新版本: - v{{ $updater->latest_version }} + v{{ $info['latest_version'] }}
当前版本: - v{{ $updater->current_version }} + v{{ $info['current_version'] }}
发布时间: - {{ $updater->update_time }} + {{ Utils::getTimeFormatted($info['release_time']) }}
更新日志: - {!! nl2br($updater->getUpdateInfo()['releases'][$updater->latest_version]['release_note']) !!} + {!! nl2br($info['release_note']) ?: "无内容" !!}
下载地址: - @GitHub + 点击下载完整安装包
@else @@ -75,13 +78,17 @@ 当前版本: - v{{ $updater->current_version }} + v{{ $info['current_version'] }} 发布时间: - {{ @date('Y-m-d H:i:s', $updater->getUpdateInfo()['releases'][$updater->current_version]['release_time']) }} + @if (isset($info['release_time'])) + {{ Utils::getTimeFormatted($info['release_time']) }} + @else + 当前版本为未发布测试版 + @endif @@ -89,7 +96,7 @@ @endif
@@ -120,12 +127,19 @@ if ($key != "option" && $key != "submit") Option::set($key, $value); } + echo '
设置已保存。
'; - } ?> + } + + try { + $response = file_get_contents(option('update_source')); + } catch (Exception $e) { + echo '
无法访问当前更新源。详细信息:'.$e->getMessage().'
'; + } + + ?> - - - @@ -164,13 +171,23 @@ -@endsection + -@section('script') - @endsection diff --git a/resources/views/setup/updates/success.tpl b/resources/views/setup/updates/success.tpl index d290ca65..fb7f82c4 100644 --- a/resources/views/setup/updates/success.tpl +++ b/resources/views/setup/updates/success.tpl @@ -6,7 +6,7 @@

数据库升级成功,欢迎使用 Blessing Skin Server {{ config('app.version') }}!

{{-- if any tip is given --}} -@if (isset($tips)) +@if (!empty($tips))

升级提示:

检查更新 @@ -135,19 +149,12 @@
更新源 - + - @foreach ($updater->getUpdateSources() as $key => $value) -

{!! $value['description'] !!}

- @endforeach +

可用的更新源列表可以在这里查看:@GitHub Wiki