From d70d50237718d4bade7381c3973fe8b97e3e8dae Mon Sep 17 00:00:00 2001 From: "iVampireSP.com" Date: Tue, 3 Jan 2023 19:42:52 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=20=E9=9B=86=E7=BE=A4?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E6=96=87=E4=BB=B6=E5=90=8C=E6=AD=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + app/Console/Commands/Cluster/ReportSystem.php | 33 +++++ app/Console/Commands/Cluster/Sync.php | 85 +++++++++++ app/Console/Commands/Cluster/Upload.php | 137 ++++++++++++++++++ app/Console/Commands/Init.php | 49 +++++++ app/Console/Kernel.php | 30 +++- composer.json | 1 + composer.lock | 5 +- 8 files changed, 331 insertions(+), 10 deletions(-) create mode 100644 app/Console/Commands/Cluster/ReportSystem.php create mode 100644 app/Console/Commands/Cluster/Sync.php create mode 100644 app/Console/Commands/Cluster/Upload.php create mode 100644 app/Console/Commands/Init.php diff --git a/.gitignore b/.gitignore index c3716e4..a8602e4 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ .env .env.backup .env.production +.env.slave .phpunit.result.cache Homestead.json Homestead.yaml diff --git a/app/Console/Commands/Cluster/ReportSystem.php b/app/Console/Commands/Cluster/ReportSystem.php new file mode 100644 index 0000000..b546514 --- /dev/null +++ b/app/Console/Commands/Cluster/ReportSystem.php @@ -0,0 +1,33 @@ +info('正在下载配置。'); + + $node_type = config('settings.node_type'); + + $cache_key = "cluster:${node_type}_config"; + $config = Cache::get($cache_key); + + if ($config) { + $this->info('检查下载目录的 MD5 值。'); + $config_md5_key = "cluster:${node_type}_config_md5"; + $config_md5 = Cache::get($config_md5_key, ''); + + $md5 = md5($config); + if ($md5 !== $config_md5) { + $this->error('下载目录 MD5 值被篡改。请尝试从其他节点重新同步。'); + return CommandAlias::FAILURE; + } + + // 将缓存写入文件 + $this->info('正在写入文件。'); + Storage::disk('local')->put('cluster/config.zip', $config); + + $path = Storage::disk('local')->path('cluster/config.zip'); + + // 删除 config 目录 + $this->info('正在删除 config 目录。'); + $cache_path = base_path('config'); + + // exec + $cmd = "rm -rf ${cache_path}"; + exec($cmd); + + $this->info('正在解压缩。'); + + $zip = new ZipArchive(); + $zip->open($path); + $zip->extractTo(base_path()); + $zip->close(); + + $this->info('正在清理。'); + + // 删除目录 + Storage::disk('local')->deleteDirectory('cluster'); + } else { + $this->error('没有找到缓存。请尝试从其他节点重新同步。'); + return CommandAlias::FAILURE; + } + + + return CommandAlias::SUCCESS; + } +} diff --git a/app/Console/Commands/Cluster/Upload.php b/app/Console/Commands/Cluster/Upload.php new file mode 100644 index 0000000..3d68f8a --- /dev/null +++ b/app/Console/Commands/Cluster/Upload.php @@ -0,0 +1,137 @@ +info('正在初始化节点。'); + + $node_type = config('settings.node_type'); + + if ($node_type === 'master') { + $this->warn('此节点为主节点,将同时上传两份版本(如果有 .env.slave 的话)。'); + + // 上传 master + $this->upload('master'); + + } + + + // 检测 .env.slave 是否存在 + if (file_exists(base_path('.env.slave'))) { + // 备份当前的 .env 文件为 .env.temp + $this->info('正在备份 .env 文件。'); + copy(base_path('.env'), base_path('.env.temp')); + + // 复制 .env.slave 为 .env + $this->info('正在复制 .env.slave 文件。'); + copy(base_path('.env.slave'), base_path('.env')); + + $this->upload('slave'); + + // 恢复 .env 文件 + $this->info('正在恢复 .env 文件。'); + copy(base_path('.env.temp'), base_path('.env')); + + // 删除 .env.temp + unlink(base_path('.env.temp')); + + $this->info('节点初始化完成。'); + } + + // if is local + if (app()->environment() === 'local') { + $this->info('清理开发节点。'); + + Artisan::call('route:clear'); + Artisan::call('config:clear'); + } + + return CommandAlias::SUCCESS; + } + + public function addFileToZip(string $path, ZipArchive $zip): void + { + $handler = opendir($path); + while (($filename = readdir($handler)) !== false) { + if ($filename != '.' && $filename != '..') { + if (is_dir($path . '/' . $filename)) { + $this->addFileToZip($path . '/' . $filename, $zip); + } else { + $zip->addFile($path . '/' . $filename); + } + } + } + @closedir($handler); + + } + + public function upload($node_type) + { + $this->warn("正在上传 ${node_type} 文件。"); + $this->info('正在打包 config 目录。'); + + if ($node_type === 'master') { + // 相对路径 + $cache = 'config'; + + $cacheZip = $cache . '.zip'; + $zip = new ZipArchive(); + $zip->open($cacheZip, ZipArchive::CREATE); + $this->addFileToZip($cache, $zip); + $zip->close(); + + $this->info('正在上传 config 目录。'); + + $cache_key = "cluster:${node_type}_config"; + Cache::forever($cache_key, file_get_contents($cacheZip)); + + // md5 + $this->info('正在报告 cache 目录的 MD5 值。'); + $cache_md5_key = "cluster:${node_type}_config_md5"; + Cache::forever($cache_md5_key, md5_file($cacheZip)); + + unlink($cacheZip); + + } + + // 上传 .env 文件 + $this->info('正在上传 .env 文件。'); + $env_key = "cluster:${node_type}_env"; + Cache::forever($env_key, file_get_contents(base_path('.env'))); + + // 上传 .env 文件的 MD5 + $this->info('正在报告 .env 文件的 MD5 值。'); + $env_md5_key = "cluster:${node_type}_env_md5"; + Cache::forever($env_md5_key, md5_file(base_path('.env'))); + + $this->info('完成。'); + } +} diff --git a/app/Console/Commands/Init.php b/app/Console/Commands/Init.php new file mode 100644 index 0000000..b36d130 --- /dev/null +++ b/app/Console/Commands/Init.php @@ -0,0 +1,49 @@ +info('正在删除 bootstrap/cache 目录。'); + $cache_path = base_path('bootstrap/cache'); + $files = glob($cache_path . '/*'); + foreach ($files as $file) { + if (is_file($file)) { + unlink($file); + } + } + + Artisan::call('route:clear'); + Artisan::call('config:clear'); + Artisan::call('view:clear'); + + Artisan::call('optimize'); + + return CommandAlias::SUCCESS; + } +} diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index e4af124..694d816 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -26,6 +26,27 @@ class Kernel extends ConsoleKernel * @return void */ protected function schedule(Schedule $schedule): void + { + if (config('settings.node_type') === 'master') { + $this->registerMasterSchedules($schedule); + } else { + $this->registerSlaveSchedules($schedule); + } + } + + /** + * Register the commands for the application. + * + * @return void + */ + protected function commands(): void + { + $this->load(__DIR__ . '/Commands'); + + require base_path('routes/console.php'); + } + + private function registerMasterSchedules(Schedule $schedule): void { // 清理过期的 Token $schedule->command('sanctum:prune-expired --hours=24')->daily(); @@ -63,15 +84,8 @@ protected function schedule(Schedule $schedule): void $schedule->job(new SetBirthdayGroupJob())->dailyAt('00:00'); } - /** - * Register the commands for the application. - * - * @return void - */ - protected function commands(): void + private function registerSlaveSchedules(Schedule $schedule): void { - $this->load(__DIR__ . '/Commands'); - require base_path('routes/console.php'); } } diff --git a/composer.json b/composer.json index c6dd458..2bad9bd 100644 --- a/composer.json +++ b/composer.json @@ -9,6 +9,7 @@ "license": "MIT", "require": { "php": "^8.1", + "ext-zip": "^1.19", "doctrine/dbal": "^3.4", "erusev/parsedown": "^1.7", "fruitcake/laravel-cors": "^3.0", diff --git a/composer.lock b/composer.lock index 50fb0a9..89d3b23 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "9ba10b0e61eac712b437b33b0ab61fbe", + "content-hash": "81fa8fb300376dbf0ae3eb8771d2018f", "packages": [ { "name": "bacon/bacon-qr-code", @@ -11696,7 +11696,8 @@ "prefer-stable": true, "prefer-lowest": false, "platform": { - "php": "^8.1" + "php": "^8.1", + "ext-zip": "^1.19" }, "platform-dev": [], "plugin-api-version": "2.3.0"