Lae/app/Console/Commands/Cluster/Upload.php

164 lines
5.2 KiB
PHP

<?php
namespace App\Console\Commands\Cluster;
use App\Support\ClusterSupport;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Artisan;
use Symfony\Component\Console\Command\Command as CommandAlias;
use ZipArchive;
class Upload extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'cluster:upload';
/**
* The console command description.
*
* @var string
*/
protected $description = '将此节点配置文件上传到集群中。';
/**
* Execute the console command.
*
* @return int
*/
public function handle(): int
{
$node_type = config('settings.node.type');
if ($node_type === 'slave') {
$this->info('正在同步从节点配置文件。');
$this->upload('slave');
$this->info('从节点配置文件同步完成。');
return CommandAlias::SUCCESS;
}
$this->warn('此节点为主节点,将同时上传两份版本(如果有 .env.slave 的话)。以及让边缘节点重载 SSL。');
// 上传 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'));
}
ClusterSupport::publish('config.updated');
$this->info('节点初始化完成。');
if (app()->environment() === 'local') {
$this->info('清理开发节点。');
Artisan::call('route:clear');
Artisan::call('config:clear');
}
return CommandAlias::SUCCESS;
}
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 = "{$node_type}_config_zip";
ClusterSupport::forever($cache_key, file_get_contents($cacheZip));
// md5
$this->info('正在报告 cache 目录的 MD5 值。');
$cache_md5_key = "{$node_type}_config_zip_md5";
ClusterSupport::forever($cache_md5_key, md5_file($cacheZip));
unlink($cacheZip);
// 上传 config/secrets/ssl_fullchain.pem 和 config/secrets/ssl_privkey.pem
$ssl_fullchain_key = 'config/secrets/ssl_fullchain.pem';
$ssl_privkey_key = 'config/secrets/ssl_privkey.pem';
if (file_exists(base_path($ssl_fullchain_key)) && file_exists(base_path($ssl_privkey_key))) {
$this->info('正在上传 SSL 证书。');
ClusterSupport::forever('ssl_fullchain', file_get_contents(base_path($ssl_fullchain_key)));
ClusterSupport::forever('ssl_privkey', file_get_contents(base_path($ssl_privkey_key)));
// 计算 md5
$ssl_fullchain_md5 = md5_file(base_path($ssl_fullchain_key));
$ssl_privkey_md5 = md5_file(base_path($ssl_privkey_key));
$this->info('正在报告 SSL 证书的 MD5 值。');
ClusterSupport::forever('ssl_fullchain_md5', $ssl_fullchain_md5);
ClusterSupport::forever('ssl_privkey_md5', $ssl_privkey_md5);
ClusterSupport::publish('config.ssl.updated');
} else {
$this->warn('SSL 证书不存在,跳过。');
}
}
// 上传 .env 文件
$this->info('正在上传 .env 文件。');
$env_key = "{$node_type}_env";
ClusterSupport::forever($env_key, file_get_contents(base_path('.env')));
// 上传 .env 文件的 MD5
$this->info('正在报告 .env 文件的 MD5 值。');
$env_md5_key = "{$node_type}_env_md5";
ClusterSupport::forever($env_md5_key, md5_file(base_path('.env')));
$this->info('完成。');
}
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);
}
}