SwrpcServerCom.php 6.4 KB
<?php

namespace AukeySwrpc\Commands;


use AukeySwrpc\ClientManger;
use Illuminate\Console\Command;
use Monolog\Handler\StreamHandler;
use Monolog\Logger;
use Nwidart\Modules\Facades\Module;
use AukeySwrpc\Client;
use AukeySwrpc\LogicService;
use AukeySwrpc\Register\Consul;
use AukeySwrpc\Request\SystemRequest;
use AukeySwrpc\Server;

/**
 * Class SwrpcServerCom
 *
 * @package App\Console\Commands
 * @author pengjch 2024314 12:13:15
 */
class SwrpcServerCom extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'swrpc:server {action=start} {--module=}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'swrpc服务端';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    protected $pidFile = __DIR__ . '/swrpc.pid';

    /**
     * Execute the console command.
     *
     * @return int
     */
    public function handle()
    {
        $action = $this->argument('action');
        if ($action == 'start') {
            $this->start();
        } elseif ($action == 'stop') {
            $this->stop();
        } elseif ($action == 'status') {
            $this->status();
        } elseif ($action == 'restart') {
            $this->stop();
            sleep(2);
            $this->start();
        }
        return 0;
    }

    protected function status()
    {
        $pid = @file_get_contents($this->pidFile);
        if (!$pid) {
            $this->error('swrpc未启动');
            return;
        }
        $res = posix_kill($pid, 0);
        if (!$res) {
            $this->error('swrpc未启动或已退出');
            return;
        }

        $client = ClientManger::getInstance(env('SWRPC_SERVER_NAME'));
        $records = $client->send(SystemRequest::create('stats', []));
        $this->info('----------swrpc服务端状态---------');
        foreach ((array)$records as $key => $value) {
            $this->info($key . ': ' . $value);
        }
    }

    protected function stop()
    {
        $pid = @file_get_contents($this->pidFile);
        if (!$pid) {
            $this->error('swrpc未启动');
            return;
        }

        $res = posix_kill($pid, SIGTERM);
        $res ? $this->info('swrpc停止成功') : $this->info('swrpc停止失败');
    }

    protected function start()
    {
        $pid = @file_get_contents($this->pidFile);
        if ($pid && posix_kill($pid, 0)) {
            $this->error('swrpc已启动,请不要重复启动');
            return -1;
        }

        $name = env('SWRPC_SERVER_NAME');
        if (!$name) {
            $this->error('SWRPC_SERVER_NAME未设置');
            return -1;
        }
        $host = env('SWRPC_SERVER_HOST');
        if (!$host) {
            $this->error('SWRPC_SERVER_HOST未设置');
            return -1;
        }
        $port = env('SWRPC_SERVER_PORT');
        if (!$port) {
            $this->error('SWRPC_SERVER_PORT未设置');
            return -1;
        }
        $logger = new Logger('swrpc');
        $logger->pushHandler(new StreamHandler(STDOUT, Logger::INFO));
        $server = new Server($name, $host, $port, [
            'worker_num' => swoole_cpu_num(),
            'pid_file'   => $this->pidFile,
        ], SWOOLE_PROCESS, SWOOLE_SOCK_TCP, $logger);

        if ($regiserUri = env('SWRPC_REGISTER_URI')) {
            $server->addRegister(new Consul($regiserUri));
        }

        $filters = [];
        $specifyModules = $this->option('module') ? explode(',', $this->option('module')) : [];
        $loader = require base_path('vendor').'/autoload.php';
        // 获取注册的命名空间前缀并筛选出 Composer 包的命名空间
        $prefixes = $loader->getPrefixesPsr4();
        foreach ($prefixes as $key => $prefix) {
            //如果有指定moudle,则只有指定的moudle会生成,否则会生成全部
            if (count($specifyModules) > 0 && !in_array($key, $specifyModules, true)) {
                continue;
            }
            $namespace = $key . 'Http\Service';
            //fetch file
            $servicePath = $prefix[0] . '/Http/Service';
            if (!is_dir($servicePath)) {
                continue;
            }

            $queues = scandir($servicePath);
            while (count($queues) > 0) {
                $file = array_shift($queues);
                if ($file == '.' || $file == '..' || in_array($file, $filters)) {
                    continue;
                }
                //支持嵌套多层service目录
                if (is_dir($servicePath . '/' . $file)) {
                    $childrenFiles = scandir($servicePath . '/' . $file);
                    foreach ($childrenFiles as $f) {
                        if ($f == '.' || $f == '..' || in_array($f, $filters)) {
                            continue;
                        }
                        array_push($queues, $file . '/' . $f);
                    }
                    continue;
                }
                $class = substr($file, 0, strrpos($file, '.'));
                $serviceObj = $this->build($namespace, $class);
                if (!$serviceObj) {
                    continue;
                }
                if (!($serviceObj instanceof LogicService)) {
                    $this->warn('没有继承\Swrpc\LogicService类,跳过' . get_class($serviceObj));
                    continue;
                }

                $server->addService($serviceObj);
            }
        }

        $server->start();
    }

    /**
     * build
     *
     * @param $namespace
     * @param $class
     * @return object|null
     * @author pengjch 202435 16:51:18
     */
    protected function build($namespace, $class): ?object
    {
        $serviceClass = str_replace('/', '\\', $namespace . '\\' . $class);
        if (!class_exists($serviceClass)) {
            $this->error($serviceClass . '类不存在');
            return null;
        }

        try {
            $rf = new \ReflectionClass($serviceClass);
        } catch (\ReflectionException $e) {
            $this->error($serviceClass . $e->getMessage());
            return null;
        }

        try {
            return $rf->newInstance();
        } catch (\ReflectionException $e) {
            $this->error($serviceClass . $e->getMessage());
            return null;
        }
    }
}