diff --git a/bin/phpunit-swoole b/bin/phpunit-swoole
index 1bc0ee32..9a2898b1 100755
--- a/bin/phpunit-swoole
+++ b/bin/phpunit-swoole
@@ -9,10 +9,11 @@ use PHPUnit\Runner\Version;
use PHPUnit\TextUI\TestRunner;
use Swoole\Coroutine;
use ZM\Annotation\Swoole\OnStart;
-use ZM\Command\RunServerCommand;
+use ZM\Command\Server\ServerStartCommand;
use ZM\Console\Console;
use ZM\ConsoleApplication;
use ZM\Event\EventManager;
+use ZM\Exception\ConfigException;
use ZM\Framework;
use ZM\Store\ZMAtomic;
use ZM\Utils\ZMUtil;
@@ -71,7 +72,7 @@ chdir(__DIR__ . '/../');
$options = array_map(function ($x) {
return $x->getDefault();
-}, RunServerCommand::exportDefinition()->getOptions());
+}, ServerStartCommand::exportDefinition()->getOptions());
$options['disable-safe-exit'] = true;
$options['worker-num'] = 1;
$options['private-mode'] = true;
@@ -90,7 +91,12 @@ spl_autoload_register(static function ($class) {
}, true, true);
Console::setLevel(0);
-$framework = new Framework($options);
+try {
+ $framework = new Framework($options);
+} catch (ConfigException $e) {
+ echo $e->getMessage();
+ exit(1);
+}
$start = new OnStart();
$start->method = function () {
try {
diff --git a/bin/start b/bin/start
index d2f111be..c3eb7aaf 100755
--- a/bin/start
+++ b/bin/start
@@ -5,7 +5,10 @@
# author: crazywhalecc
# since: 2.5.0
-if [ -f "$(pwd)/runtime/php" ]; then
+if [ "$ZM_CUSTOM_PHP_PATH" != "" ]; then
+ echo "* Using PHP executable: ""$ZM_CUSTOM_PHP_PATH"
+ executable="$ZM_CUSTOM_PHP_PATH"
+elif [ -f "$(pwd)/runtime/php" ]; then
executable="$(pwd)/runtime/php"
echo "* Framework started with built-in php."
else
diff --git a/composer.json b/composer.json
index 85c330d4..90654437 100644
--- a/composer.json
+++ b/composer.json
@@ -29,6 +29,7 @@
"symfony/routing": "~6.0 || ~5.0 || ~4.0 || ~3.0",
"zhamao/connection-manager": "^1.0",
"zhamao/console": "^1.0",
+ "zhamao/logger": "dev-master",
"zhamao/request": "^1.1"
},
"require-dev": {
diff --git a/src/ZM/Command/Daemon/DaemonReloadCommand.php b/src/ZM/Command/Daemon/DaemonReloadCommand.php
deleted file mode 100644
index 0b0fe80f..00000000
--- a/src/ZM/Command/Daemon/DaemonReloadCommand.php
+++ /dev/null
@@ -1,27 +0,0 @@
-setDescription('重载框架');
- }
-
- protected function execute(InputInterface $input, OutputInterface $output): int
- {
- parent::execute($input, $output);
- Process::kill(intval($this->daemon_file['pid']), SIGUSR1);
- $output->writeln('成功重载!');
- return 0;
- }
-}
diff --git a/src/ZM/Command/Daemon/DaemonStatusCommand.php b/src/ZM/Command/Daemon/DaemonStatusCommand.php
deleted file mode 100644
index 19ab4b8d..00000000
--- a/src/ZM/Command/Daemon/DaemonStatusCommand.php
+++ /dev/null
@@ -1,35 +0,0 @@
-setDescription('查看框架的运行状态');
- }
-
- protected function execute(InputInterface $input, OutputInterface $output): int
- {
- parent::execute($input, $output);
- $output->writeln('框架' . ($this->daemon_file['daemon'] ? '以守护进程模式' : '') . '运行中,pid:' . $this->daemon_file['pid'] . '');
- if ($this->daemon_file['daemon']) {
- $output->writeln('----- 以下是stdout内容 -----');
- $stdout = file_get_contents($this->daemon_file['stdout']);
- $stdout = explode("\n", $stdout);
- for ($i = 15; $i > 0; --$i) {
- if (isset($stdout[count($stdout) - $i])) {
- echo $stdout[count($stdout) - $i] . PHP_EOL;
- }
- }
- }
- return 0;
- }
-}
diff --git a/src/ZM/Command/Daemon/DaemonStopCommand.php b/src/ZM/Command/Daemon/DaemonStopCommand.php
deleted file mode 100644
index f36e4e04..00000000
--- a/src/ZM/Command/Daemon/DaemonStopCommand.php
+++ /dev/null
@@ -1,37 +0,0 @@
-setDescription('停止运行的框架');
- }
-
- protected function execute(InputInterface $input, OutputInterface $output): int
- {
- parent::execute($input, $output);
- Process::kill(intval($this->daemon_file['pid']), SIGTERM);
- $i = 10;
- while (Framework::getProcessState(ZM_PROCESS_MASTER) !== false && $i > 0) {
- sleep(1);
- --$i;
- }
- if ($i === 0) {
- $output->writeln('停止失败,请检查进程pid #' . $this->daemon_file['pid'] . ' 是否响应!');
- } else {
- $output->writeln('成功停止!');
- }
- return 0;
- }
-}
diff --git a/src/ZM/Command/PureHttpCommand.php b/src/ZM/Command/PureHttpCommand.php
index d8a4818d..15352844 100644
--- a/src/ZM/Command/PureHttpCommand.php
+++ b/src/ZM/Command/PureHttpCommand.php
@@ -16,7 +16,7 @@ use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use ZM\Config\ZMConfig;
use ZM\Console\Console;
-use ZM\Framework;
+use ZM\Logger\TablePrinter;
use ZM\Store\ZMAtomic;
use ZM\Utils\DataProvider;
use ZM\Utils\HttpUtil;
@@ -55,7 +55,8 @@ class PureHttpCommand extends Command
'web_root' => realpath($input->getArgument('dir') ?? '.'),
'index' => implode(',', $index),
];
- Framework::printProps($out, $tty_width);
+ $printer = new TablePrinter($out);
+ $printer->printAll();
$server = new Server($host, $port);
$server->set(ZMConfig::get('global', 'swoole'));
Console::init(2, $server);
diff --git a/src/ZM/Command/Daemon/DaemonCommand.php b/src/ZM/Command/Server/ServerCommand.php
similarity index 50%
rename from src/ZM/Command/Daemon/DaemonCommand.php
rename to src/ZM/Command/Server/ServerCommand.php
index 27d17dce..173c7efc 100644
--- a/src/ZM/Command/Daemon/DaemonCommand.php
+++ b/src/ZM/Command/Server/ServerCommand.php
@@ -2,23 +2,31 @@
declare(strict_types=1);
-namespace ZM\Command\Daemon;
+namespace ZM\Command\Server;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
-use ZM\Framework;
+use ZM\Exception\ZMKnownException;
+use ZM\Utils\Manager\ProcessManager;
-abstract class DaemonCommand extends Command
+abstract class ServerCommand extends Command
{
protected $daemon_file;
+ /**
+ * @throws ZMKnownException
+ */
protected function execute(InputInterface $input, OutputInterface $output): int
{
- $file = Framework::getProcessState(ZM_PROCESS_MASTER);
+ $file = ProcessManager::getProcessState(ZM_PROCESS_MASTER);
if ($file === false || posix_getsid(intval($file['pid'])) === false) {
$output->writeln('未检测到正在运行的守护进程或框架进程!');
- Framework::removeProcessState(ZM_PROCESS_MASTER);
+ if (ProcessManager::isStateEmpty()) {
+ ProcessManager::removeProcessState(ZM_PROCESS_MASTER);
+ } else {
+ $output->writeln('检测到可能残留的守护进程或框架进程,请使用命令关闭:server:stop --force');
+ }
exit(1);
}
$this->daemon_file = $file;
diff --git a/src/ZM/Command/Server/ServerReloadCommand.php b/src/ZM/Command/Server/ServerReloadCommand.php
index 8d87503c..7829cd13 100644
--- a/src/ZM/Command/Server/ServerReloadCommand.php
+++ b/src/ZM/Command/Server/ServerReloadCommand.php
@@ -7,9 +7,8 @@ namespace ZM\Command\Server;
use Swoole\Process;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
-use ZM\Command\Daemon\DaemonCommand;
-class ServerReloadCommand extends DaemonCommand
+class ServerReloadCommand extends ServerCommand
{
protected static $defaultName = 'server:reload';
diff --git a/src/ZM/Command/RunServerCommand.php b/src/ZM/Command/Server/ServerStartCommand.php
similarity index 90%
rename from src/ZM/Command/RunServerCommand.php
rename to src/ZM/Command/Server/ServerStartCommand.php
index 6633bb6a..8fbf706d 100644
--- a/src/ZM/Command/RunServerCommand.php
+++ b/src/ZM/Command/Server/ServerStartCommand.php
@@ -2,19 +2,22 @@
declare(strict_types=1);
-namespace ZM\Command;
+namespace ZM\Command\Server;
-use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Input\InputDefinition;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
+use ZM\Exception\ConfigException;
+use ZM\Exception\ZMKnownException;
use ZM\Framework;
+use ZM\Utils\Manager\ProcessManager;
-class RunServerCommand extends Command
+class ServerStartCommand extends ServerCommand
{
protected static $defaultName = 'server';
- public static function exportDefinition()
+ public static function exportDefinition(): InputDefinition
{
$cmd = new self();
$cmd->configure();
@@ -54,6 +57,10 @@ class RunServerCommand extends Command
$this->setHelp('直接运行可以启动');
}
+ /**
+ * @throws ZMKnownException
+ * @throws ConfigException
+ */
protected function execute(InputInterface $input, OutputInterface $output): int
{
if (($opt = $input->getOption('env')) !== null) {
@@ -62,7 +69,7 @@ class RunServerCommand extends Command
return 1;
}
}
- $state = Framework::getProcessState(ZM_PROCESS_MASTER);
+ $state = ProcessManager::getProcessState(ZM_PROCESS_MASTER);
if (!$input->getOption('no-state-check')) {
if (is_array($state) && posix_getsid($state['pid'] ?? -1) !== false) {
$output->writeln("检测到已经在 pid: {$state['pid']} 进程启动了框架!");
diff --git a/src/ZM/Command/Server/ServerStatusCommand.php b/src/ZM/Command/Server/ServerStatusCommand.php
index d3abb6ff..4b0fe449 100644
--- a/src/ZM/Command/Server/ServerStatusCommand.php
+++ b/src/ZM/Command/Server/ServerStatusCommand.php
@@ -6,9 +6,8 @@ namespace ZM\Command\Server;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
-use ZM\Command\Daemon\DaemonCommand;
-class ServerStatusCommand extends DaemonCommand
+class ServerStatusCommand extends ServerCommand
{
protected static $defaultName = 'server:status';
diff --git a/src/ZM/Command/Server/ServerStopCommand.php b/src/ZM/Command/Server/ServerStopCommand.php
index c78eeefc..d2ef5006 100644
--- a/src/ZM/Command/Server/ServerStopCommand.php
+++ b/src/ZM/Command/Server/ServerStopCommand.php
@@ -8,11 +8,10 @@ use Swoole\Process;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
-use ZM\Command\Daemon\DaemonCommand;
-use ZM\Framework;
use ZM\Utils\DataProvider;
+use ZM\Utils\Manager\ProcessManager;
-class ServerStopCommand extends DaemonCommand
+class ServerStopCommand extends ServerCommand
{
protected static $defaultName = 'server:stop';
@@ -47,7 +46,7 @@ class ServerStopCommand extends DaemonCommand
Process::kill(intval($this->daemon_file['pid']), SIGTERM);
}
$i = 10;
- while (Framework::getProcessState(ZM_PROCESS_MASTER) !== false && $i > 0) {
+ while (ProcessManager::getProcessState(ZM_PROCESS_MASTER) !== false && $i > 0) {
sleep(1);
--$i;
}
diff --git a/src/ZM/Config/ZMConfig.php b/src/ZM/Config/ZMConfig.php
index 8a555860..64d0c425 100644
--- a/src/ZM/Config/ZMConfig.php
+++ b/src/ZM/Config/ZMConfig.php
@@ -86,7 +86,7 @@ class ZMConfig
self::$config[$head_name] = self::loadConfig($head_name);
}
// global.remote_terminal
- // 根据切分来寻找子配置
+ Console::debug('根据切分来寻找子配置: ' . $name);
$obj = self::$config[$head_name];
foreach ($separated as $key) {
if (isset($obj[$key])) {
diff --git a/src/ZM/ConsoleApplication.php b/src/ZM/ConsoleApplication.php
index 1a2d9f11..ad8ef2bf 100644
--- a/src/ZM/ConsoleApplication.php
+++ b/src/ZM/ConsoleApplication.php
@@ -11,17 +11,14 @@ use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use ZM\Command\BuildCommand;
use ZM\Command\CheckConfigCommand;
-use ZM\Command\Daemon\DaemonReloadCommand;
-use ZM\Command\Daemon\DaemonStatusCommand;
-use ZM\Command\Daemon\DaemonStopCommand;
use ZM\Command\Generate\SystemdGenerateCommand;
use ZM\Command\InitCommand;
use ZM\Command\Module\ModuleListCommand;
use ZM\Command\Module\ModulePackCommand;
use ZM\Command\Module\ModuleUnpackCommand;
use ZM\Command\PureHttpCommand;
-use ZM\Command\RunServerCommand;
use ZM\Command\Server\ServerReloadCommand;
+use ZM\Command\Server\ServerStartCommand;
use ZM\Command\Server\ServerStatusCommand;
use ZM\Command\Server\ServerStopCommand;
use ZM\Exception\InitException;
@@ -84,13 +81,10 @@ class ConsoleApplication extends Application
}
$this->addCommands([
- new DaemonStatusCommand(),
- new DaemonReloadCommand(),
- new DaemonStopCommand(),
- new RunServerCommand(), // 运行主服务的指令控制器
new ServerStatusCommand(),
- new ServerStopCommand(),
new ServerReloadCommand(),
+ new ServerStopCommand(),
+ new ServerStartCommand(), // 运行主服务的指令控制器
new PureHttpCommand(), // 纯HTTP服务器指令
new SystemdGenerateCommand(),
]);
diff --git a/src/ZM/Event/SwooleEvent/OnManagerStart.php b/src/ZM/Event/SwooleEvent/OnManagerStart.php
index 4c324f1a..11fefe80 100644
--- a/src/ZM/Event/SwooleEvent/OnManagerStart.php
+++ b/src/ZM/Event/SwooleEvent/OnManagerStart.php
@@ -46,7 +46,7 @@ class OnManagerStart implements SwooleEvent
if (!Framework::$argv['disable-safe-exit']) {
SignalListener::signalManager();
}
- Framework::saveProcessState(ZM_PROCESS_MANAGER, $server->manager_pid);
+ ProcessManager::saveProcessState(ZM_PROCESS_MANAGER, $server->manager_pid);
ProcessManager::createUserProcess('monitor', function () use ($server) {
Process::signal(SIGINT, function () {
diff --git a/src/ZM/Event/SwooleEvent/OnManagerStop.php b/src/ZM/Event/SwooleEvent/OnManagerStop.php
index c1b92bf7..79fed871 100644
--- a/src/ZM/Event/SwooleEvent/OnManagerStop.php
+++ b/src/ZM/Event/SwooleEvent/OnManagerStop.php
@@ -8,7 +8,6 @@ use Swoole\Process;
use ZM\Annotation\Swoole\SwooleHandler;
use ZM\Console\Console;
use ZM\Event\SwooleEvent;
-use ZM\Framework;
use ZM\Utils\Manager\ProcessManager;
/**
@@ -25,6 +24,6 @@ class OnManagerStop implements SwooleEvent
}
}
Console::verbose('进程 Manager 已停止!');
- Framework::removeProcessState(ZM_PROCESS_MANAGER);
+ ProcessManager::removeProcessState(ZM_PROCESS_MANAGER);
}
}
diff --git a/src/ZM/Event/SwooleEvent/OnShutdown.php b/src/ZM/Event/SwooleEvent/OnShutdown.php
index d2f108c6..3cafa7c4 100644
--- a/src/ZM/Event/SwooleEvent/OnShutdown.php
+++ b/src/ZM/Event/SwooleEvent/OnShutdown.php
@@ -10,8 +10,8 @@ use Swoole\Server;
use ZM\Annotation\Swoole\SwooleHandler;
use ZM\Console\Console;
use ZM\Event\SwooleEvent;
-use ZM\Framework;
use ZM\Utils\DataProvider;
+use ZM\Utils\Manager\ProcessManager;
/**
* Class OnShutdown
@@ -22,7 +22,7 @@ class OnShutdown implements SwooleEvent
public function onCall(Server $server)
{
Console::verbose('正在关闭 Master 进程,pid=' . posix_getpid());
- Framework::removeProcessState(ZM_PROCESS_MASTER);
+ ProcessManager::removeProcessState(ZM_PROCESS_MASTER);
if (DataProvider::scanDirFiles(_zm_pid_dir()) == []) {
rmdir(_zm_pid_dir());
}
diff --git a/src/ZM/Event/SwooleEvent/OnStart.php b/src/ZM/Event/SwooleEvent/OnStart.php
index dd863e4a..07c574ec 100644
--- a/src/ZM/Event/SwooleEvent/OnStart.php
+++ b/src/ZM/Event/SwooleEvent/OnStart.php
@@ -10,6 +10,7 @@ use ZM\Config\ZMConfig;
use ZM\Console\Console;
use ZM\Event\SwooleEvent;
use ZM\Framework;
+use ZM\Utils\Manager\ProcessManager;
use ZM\Utils\SignalListener;
/**
@@ -24,7 +25,7 @@ class OnStart implements SwooleEvent
if (!Framework::$argv['disable-safe-exit']) {
SignalListener::signalMaster($server);
}
- Framework::saveProcessState(ZM_PROCESS_MASTER, $server->master_pid, [
+ ProcessManager::saveProcessState(ZM_PROCESS_MASTER, $server->master_pid, [
'stdout' => ZMConfig::get('global')['swoole']['log_file'],
'daemon' => (bool) Framework::$argv['daemon'],
]);
diff --git a/src/ZM/Event/SwooleEvent/OnWorkerExit.php b/src/ZM/Event/SwooleEvent/OnWorkerExit.php
index 8da90aaf..2cf6e870 100644
--- a/src/ZM/Event/SwooleEvent/OnWorkerExit.php
+++ b/src/ZM/Event/SwooleEvent/OnWorkerExit.php
@@ -28,6 +28,6 @@ class OnWorkerExit implements SwooleEvent
Coroutine::resume($v['coroutine']);
}
}
- Console::info('正在结束 Worker #' . $worker_id . ',进程内可能有事务在运行...');
+ Console::verbose('正在结束 Worker #' . $worker_id . ',进程内可能有事务在运行...');
}
}
diff --git a/src/ZM/Event/SwooleEvent/OnWorkerStart.php b/src/ZM/Event/SwooleEvent/OnWorkerStart.php
index a5762eaf..fb725c7d 100644
--- a/src/ZM/Event/SwooleEvent/OnWorkerStart.php
+++ b/src/ZM/Event/SwooleEvent/OnWorkerStart.php
@@ -34,11 +34,13 @@ use ZM\Exception\ZMKnownException;
use ZM\Framework;
use ZM\MySQL\MySQLPool;
use ZM\Store\LightCacheInside;
+use ZM\Store\Lock\SpinLock;
use ZM\Store\MySQL\SqlPoolStorage;
use ZM\Store\Redis\ZMRedisPool;
use ZM\Utils\DataProvider;
use ZM\Utils\Manager\CronManager;
use ZM\Utils\Manager\ModuleManager;
+use ZM\Utils\Manager\ProcessManager;
use ZM\Utils\SignalListener;
/**
@@ -58,7 +60,7 @@ class OnWorkerStart implements SwooleEvent
$this->registerWorkerContainerBindings($server);
if ($server->taskworker === false) {
- Framework::saveProcessState(ZM_PROCESS_WORKER, $server->worker_pid, ['worker_id' => $worker_id]);
+ ProcessManager::saveProcessState(ZM_PROCESS_WORKER, $server->worker_pid, ['worker_id' => $worker_id]);
zm_atomic('_#worker_' . $worker_id)->set($server->worker_pid);
if (LightCacheInside::get('wait_api', 'wait_api') !== null) {
LightCacheInside::unset('wait_api', 'wait_api');
@@ -109,12 +111,13 @@ class OnWorkerStart implements SwooleEvent
} else {
Console::warning('@OnStart 执行异常!');
}
- Console::success('Worker #' . $worker_id . ' started');
+ Console::verbose('Worker #' . $worker_id . ' started');
+ $this->gatherWorkerStartStatus();
} catch (Exception $e) {
if ($e->getMessage() === 'swoole exit') {
return;
}
- Console::error('Worker加载出错!停止服务!');
+ Console::error('Worker #' . $server->worker_id . ' 加载出错!停止服务!');
Console::error(zm_internal_errcode('E00030') . 'Uncaught ' . get_class($e) . ': ' . $e->getMessage() . "\n" . $e->getTraceAsString());
Process::kill($server->master_pid, SIGTERM);
return;
@@ -128,13 +131,13 @@ class OnWorkerStart implements SwooleEvent
}
} else {
// 这里是TaskWorker初始化的内容部分
- Framework::saveProcessState(ZM_PROCESS_TASKWORKER, $server->worker_pid, ['worker_id' => $worker_id]);
+ ProcessManager::saveProcessState(ZM_PROCESS_TASKWORKER, $server->worker_pid, ['worker_id' => $worker_id]);
try {
Framework::$server = $server;
$this->loadAnnotations();
- Console::success('TaskWorker #' . $server->worker_id . ' started');
+ Console::verbose('TaskWorker #' . $server->worker_id . ' started');
} catch (Exception $e) {
- Console::error('Worker加载出错!停止服务!');
+ Console::error('TaskWorker #' . $server->worker_id . ' 加载出错!停止服务!');
Console::error(zm_internal_errcode('E00030') . $e->getMessage() . "\n" . $e->getTraceAsString());
Process::kill($server->master_pid, SIGTERM);
return;
@@ -314,4 +317,21 @@ class OnWorkerStart implements SwooleEvent
$container->singleton(AdapterInterface::class, OneBot11Adapter::class);
}
+
+ private function gatherWorkerStartStatus()
+ {
+ SpinLock::lock('worker_start_status');
+ $ls = LightCacheInside::get('tmp_kv', 'worker_start_status') ?? [];
+ $ls[\server()->worker_id] = true;
+ if (count($ls) === \server()->setting['worker_num']) {
+ LightCacheInside::set('tmp_kv', 'worker_start_status', $ls);
+ SpinLock::unlock('worker_start_status');
+ $used = round((microtime(true) - LightCacheInside::get('tmp_kv', 'start_time')) * 1000, 3);
+ $worker_count = \server()->setting['worker_num'];
+ Console::success("{$worker_count} 个工作进程成功启动,共用时 {$used} ms");
+ } else {
+ LightCacheInside::set('tmp_kv', 'worker_start_status', $ls);
+ SpinLock::unlock('worker_start_status');
+ }
+ }
}
diff --git a/src/ZM/Event/SwooleEvent/OnWorkerStop.php b/src/ZM/Event/SwooleEvent/OnWorkerStop.php
index 3ecd8e06..16c994cf 100644
--- a/src/ZM/Event/SwooleEvent/OnWorkerStop.php
+++ b/src/ZM/Event/SwooleEvent/OnWorkerStop.php
@@ -10,8 +10,8 @@ use ZM\Config\ZMConfig;
use ZM\Console\Console;
use ZM\Container\WorkerContainer;
use ZM\Event\SwooleEvent;
-use ZM\Framework;
use ZM\Store\LightCache;
+use ZM\Utils\Manager\ProcessManager;
/**
* Class OnWorkerStop
@@ -27,6 +27,6 @@ class OnWorkerStop implements SwooleEvent
LightCache::savePersistence();
}
Console::verbose(($server->taskworker ? 'Task' : '') . "Worker #{$worker_id} 已停止 (Worker 状态码: " . $server->getWorkerStatus($worker_id) . ')');
- Framework::removeProcessState($server->taskworker ? ZM_PROCESS_TASKWORKER : ZM_PROCESS_WORKER, $worker_id);
+ ProcessManager::removeProcessState($server->taskworker ? ZM_PROCESS_TASKWORKER : ZM_PROCESS_WORKER, $worker_id);
}
}
diff --git a/src/ZM/Framework.php b/src/ZM/Framework.php
index 27667850..09062e58 100644
--- a/src/ZM/Framework.php
+++ b/src/ZM/Framework.php
@@ -18,14 +18,14 @@ use ZM\Annotation\Swoole\SwooleHandler;
use ZM\Config\ZMConfig;
use ZM\ConnectionManager\ManagerGM;
use ZM\Console\Console;
-use ZM\Console\TermColor;
use ZM\Exception\ConfigException;
-use ZM\Exception\ZMKnownException;
+use ZM\Logger\TablePrinter;
use ZM\Store\LightCache;
use ZM\Store\LightCacheInside;
use ZM\Store\Lock\SpinLock;
use ZM\Store\ZMAtomic;
use ZM\Utils\DataProvider;
+use ZM\Utils\Manager\ProcessManager;
use ZM\Utils\Terminal;
use ZM\Utils\ZMUtil;
@@ -84,9 +84,9 @@ class Framework
*/
public function __construct(array $args = [], bool $instant_mode = false)
{
- $tty_width = $this->getTtyWidth();
self::$instant_mode = $instant_mode;
self::$argv = $args;
+ Runtime::enableCoroutine(false);
// 初始化配置
ZMConfig::setDirectory(DataProvider::getSourceRootDir() . '/config');
@@ -152,7 +152,7 @@ class Framework
}
// 解析命令行参数
- $this->parseCliArgs(self::$argv, $add_port);
+ $coroutine_mode = $this->parseCliArgs(self::$argv, $add_port);
// 设置默认最长等待时间
if (!isset($this->swoole_server_config['max_wait_time'])) {
@@ -180,7 +180,7 @@ class Framework
}
$out['environment'] = ($args['env'] ?? null) === null ? 'default' : $args['env'];
$out['log_level'] = Console::getLevel();
- $out['version'] = ZM_VERSION . (LOAD_MODE === 0 ? (' (build ' . ZM_VERSION_ID . ')') : '');
+ $out['version'] = Framework::VERSION . (LOAD_MODE === 0 ? (' (build ' . ZM_VERSION_ID . ')') : '');
$out['master_pid'] = posix_getpid();
if (APP_VERSION !== 'unknown') {
$out['app_version'] = APP_VERSION;
@@ -212,7 +212,12 @@ class Framework
$conf = ZMConfig::get('global', 'remote_terminal');
$out['terminal'] = $conf['host'] . ':' . $conf['port'];
}
- self::printProps($out, $tty_width, $args['log-theme'] === null);
+ if (LOAD_MODE === 0) {
+ echo Console::setColor("* Framework started with source mode.\n", $args['log-theme'] === null ? 'yellow' : '');
+ }
+ // $this->mapOutput($out); // 汉化操作
+ $printer = new TablePrinter($out);
+ $printer->setValueColor('random')->printAll();
}
// 预览模式则直接提出
@@ -312,7 +317,14 @@ class Framework
// 非静默模式下,打印欢迎信息
if (!self::$argv['private-mode']) {
- self::printMotd($tty_width);
+ self::printMotd(isset($printer) ? $printer->fetchTerminalSize() : 79);
+ }
+
+ $global_hook = ZMConfig::get('global', 'runtime')['swoole_coroutine_hook_flags'] ?? (SWOOLE_HOOK_ALL & (~SWOOLE_HOOK_CURL));
+ if ($coroutine_mode) {
+ Runtime::enableCoroutine(true, $global_hook);
+ } else {
+ Runtime::enableCoroutine(false, SWOOLE_HOOK_ALL);
}
global $asd;
@@ -374,157 +386,21 @@ class Framework
} catch (Exception $e) {
Console::error('框架初始化出现异常,请检查!');
Console::error(zm_internal_errcode('E00010') . $e->getMessage());
+ if (strpos($e->getMessage(), 'Address already in use') !== false) {
+ if (!ProcessManager::isStateEmpty()) {
+ Console::error('检测到可能残留框架的工作进程,请先通过命令杀死:server:stop --force');
+ }
+ }
Console::debug($e);
exit;
}
}
- /**
- * 将各进程的pid写入文件,以备后续崩溃及僵尸进程处理使用
- *
- * @param int|string $pid
- * @internal
- */
- public static function saveProcessState(int $type, $pid, array $data = [])
- {
- switch ($type) {
- case ZM_PROCESS_MASTER:
- $file = _zm_pid_dir() . '/master.json';
- $json = [
- 'pid' => intval($pid),
- 'stdout' => $data['stdout'],
- 'daemon' => $data['daemon'],
- ];
- file_put_contents($file, json_encode($json, JSON_UNESCAPED_UNICODE));
- return;
- case ZM_PROCESS_MANAGER:
- $file = _zm_pid_dir() . '/manager.pid';
- file_put_contents($file, strval($pid));
- return;
- case ZM_PROCESS_WORKER:
- $file = _zm_pid_dir() . '/worker.' . $data['worker_id'] . '.pid';
- file_put_contents($file, strval($pid));
- return;
- case ZM_PROCESS_USER:
- $file = _zm_pid_dir() . '/user.' . $data['process_name'] . '.pid';
- file_put_contents($file, strval($pid));
- return;
- case ZM_PROCESS_TASKWORKER:
- $file = _zm_pid_dir() . '/taskworker.' . $data['worker_id'] . '.pid';
- file_put_contents($file, strval($pid));
- return;
- }
- }
-
- /**
- * 用于框架内部获取多进程运行状态的函数
- *
- * @param mixed $id_or_name
- * @throws ZMKnownException
- * @return false|int|mixed
- * @internal
- */
- public static function getProcessState(int $type, $id_or_name = null)
- {
- $file = _zm_pid_dir();
- switch ($type) {
- case ZM_PROCESS_MASTER:
- if (!file_exists($file . '/master.json')) {
- return false;
- }
- $json = json_decode(file_get_contents($file . '/master.json'), true);
- if ($json !== null) {
- return $json;
- }
- return false;
- case ZM_PROCESS_MANAGER:
- if (!file_exists($file . '/manager.pid')) {
- return false;
- }
- return intval(file_get_contents($file . '/manager.pid'));
- case ZM_PROCESS_WORKER:
- if (!is_int($id_or_name)) {
- throw new ZMKnownException('E99999', 'worker_id必须为整数');
- }
- if (!file_exists($file . '/worker.' . $id_or_name . '.pid')) {
- return false;
- }
- return intval(file_get_contents($file . '/worker.' . $id_or_name . '.pid'));
- case ZM_PROCESS_USER:
- if (!is_string($id_or_name)) {
- throw new ZMKnownException('E99999', 'process_name必须为字符串');
- }
- if (!file_exists($file . '/user.' . $id_or_name . '.pid')) {
- return false;
- }
- return intval(file_get_contents($file . '/user.' . $id_or_name . '.pid'));
- case ZM_PROCESS_TASKWORKER:
- if (!is_int($id_or_name)) {
- throw new ZMKnownException('E99999', 'worker_id必须为整数');
- }
- if (!file_exists($file . '/taskworker.' . $id_or_name . '.pid')) {
- return false;
- }
- return intval(file_get_contents($file . '/taskworker.' . $id_or_name . '.pid'));
- default:
- return false;
- }
- }
-
- /**
- * @param null|int|string $id_or_name
- * @throws ZMKnownException
- * @internal
- */
- public static function removeProcessState(int $type, $id_or_name = null)
- {
- switch ($type) {
- case ZM_PROCESS_MASTER:
- $file = _zm_pid_dir() . '/master.json';
- if (file_exists($file)) {
- unlink($file);
- }
- return;
- case ZM_PROCESS_MANAGER:
- $file = _zm_pid_dir() . '/manager.pid';
- if (file_exists($file)) {
- unlink($file);
- }
- return;
- case ZM_PROCESS_WORKER:
- if (!is_int($id_or_name)) {
- throw new ZMKnownException('E99999', 'worker_id必须为整数');
- }
- $file = _zm_pid_dir() . '/worker.' . $id_or_name . '.pid';
- if (file_exists($file)) {
- unlink($file);
- }
- return;
- case ZM_PROCESS_USER:
- if (!is_string($id_or_name)) {
- throw new ZMKnownException('E99999', 'process_name必须为字符串');
- }
- $file = _zm_pid_dir() . '/user.' . $id_or_name . '.pid';
- if (file_exists($file)) {
- unlink($file);
- }
- return;
- case ZM_PROCESS_TASKWORKER:
- if (!is_int($id_or_name)) {
- throw new ZMKnownException('E99999', 'worker_id必须为整数');
- }
- $file = _zm_pid_dir() . '/taskworker.' . $id_or_name . '.pid';
- if (file_exists($file)) {
- unlink($file);
- }
- return;
- }
- }
-
public function start()
{
try {
self::$loaded_files = get_included_files();
+ LightCacheInside::set('tmp_kv', 'start_time', microtime(true));
self::$server->start();
zm_atomic('server_is_stopped')->set(1);
if (!self::$argv['private-mode']) {
@@ -535,63 +411,6 @@ class Framework
}
}
- public static function printProps($out, $tty_width, $colorful = true)
- {
- $max_border = min($tty_width, 65);
- if (LOAD_MODE === 0) {
- echo Console::setColor("* Framework started with source mode.\n", $colorful ? 'yellow' : '');
- }
- echo str_pad('', $max_border, '=') . PHP_EOL;
-
- $current_line = 0;
- $line_width = [];
- $line_data = [];
- foreach ($out as $k => $v) {
- start:
- if (!isset($line_width[$current_line])) {
- $line_width[$current_line] = $max_border - 2;
- }
- // Console::info("行宽[$current_line]:".$line_width[$current_line]);
- if ($max_border >= 57) { // 很宽的时候,一行能放两个短行
- if ($line_width[$current_line] === ($max_border - 2)) { // 空行
- self::writeNoDouble($k, $v, $line_data, $line_width, $current_line, $colorful, $max_border);
- } else { // 不是空行,已经有东西了
- $tmp_line = $k . ': ' . $v;
- // Console::info("[$current_line]即将插入后面的东西[".$tmp_line."]");
- if (strlen($tmp_line) > $line_width[$current_line]) { // 地方不够,另起一行
- $line_data[$current_line] = str_replace('| ', '', $line_data[$current_line]);
- ++$current_line;
- goto start;
- } // 地方够,直接写到后面并另起一行
- $line_data[$current_line] .= $k . ': ';
- if ($colorful) {
- $line_data[$current_line] .= TermColor::color8(32);
- }
- $line_data[$current_line] .= $v;
- if ($colorful) {
- $line_data[$current_line] .= TermColor::RESET;
- }
- ++$current_line;
- }
- } else { // 不够宽,直接写单行
- self::writeNoDouble($k, $v, $line_data, $line_width, $current_line, $colorful, $max_border);
- }
- }
- foreach ($line_data as $v) {
- echo $v . PHP_EOL;
- }
- echo str_pad('', $max_border, '=') . PHP_EOL;
- }
-
- public function getTtyWidth(): int
- {
- $size = exec('stty size');
- if (empty($size)) {
- return 65;
- }
- return (int) explode(' ', trim($size))[1];
- }
-
public static function loadFrameworkState()
{
if (!file_exists(DataProvider::getDataFolder() . '.state.json')) {
@@ -609,6 +428,24 @@ class Framework
return file_put_contents(DataProvider::getDataFolder() . '.state.json', json_encode($data, 64 | 128 | 256));
}
+ public function mapOutput(array &$out)
+ {
+ $translate = [
+ 'working_dir' => '工作目录',
+ 'listen' => '监听地址',
+ 'worker' => '工作进程数',
+ 'environment' => '环境类型',
+ 'log_level' => '日志级别',
+ 'version' => '框架版本',
+ 'master_pid' => '主进程PID',
+ ];
+ foreach ($out as $k => $v) {
+ if (isset($translate[$k])) {
+ $this->arrayChangeKey($out, $k, $translate[$k]);
+ }
+ }
+ }
+
private static function printMotd($tty_width)
{
if (file_exists(DataProvider::getSourceRootDir() . '/config/motd.txt')) {
@@ -776,68 +613,14 @@ class Framework
}
}
}
- $global_hook = ZMConfig::get('global', 'runtime')['swoole_coroutine_hook_flags'] ?? (SWOOLE_HOOK_ALL & (~SWOOLE_HOOK_CURL));
- if ($coroutine_mode) {
- Runtime::enableCoroutine(true, $global_hook);
- } else {
- Runtime::enableCoroutine(false, SWOOLE_HOOK_ALL);
- }
+ return $coroutine_mode;
}
- private static function writeNoDouble($k, $v, &$line_data, &$line_width, &$current_line, $colorful, $max_border)
+ private function arrayChangeKey(array &$arr, $old_key, $new_key)
{
- $tmp_line = $k . ': ' . $v;
- // Console::info("写入[".$tmp_line."]");
- if (strlen($tmp_line) > $line_width[$current_line]) { // 输出的内容太多了,以至于一行都放不下一个,要折行
- $title_strlen = strlen($k . ': ');
- $content_len = $line_width[$current_line] - $title_strlen;
-
- $line_data[$current_line] = ' ' . $k . ': ';
- if ($colorful) {
- $line_data[$current_line] .= TermColor::color8(32);
- }
- $line_data[$current_line] .= substr($v, 0, $content_len);
- if ($colorful) {
- $line_data[$current_line] .= TermColor::RESET;
- }
- $rest = substr($v, $content_len);
- ++$current_line; // 带标题的第一行满了,折到第二行
- do {
- if ($colorful) {
- $line_data[$current_line] = TermColor::color8(32);
- }
- $line_data[$current_line] .= ' ' . substr($rest, 0, $max_border - 2);
- if ($colorful) {
- $line_data[$current_line] .= TermColor::RESET;
- }
- $rest = substr($rest, $max_border - 2);
- ++$current_line;
- } while ($rest > $max_border - 2); // 循环,直到放完
- } else { // 不需要折行
- // Console::info("不需要折行");
- $line_data[$current_line] = ' ' . $k . ': ';
- if ($colorful) {
- $line_data[$current_line] .= TermColor::color8(32);
- }
- $line_data[$current_line] .= $v;
- if ($colorful) {
- $line_data[$current_line] .= TermColor::RESET;
- }
-
- if ($max_border >= 57) {
- if (strlen($tmp_line) >= intval(($max_border - 2) / 2)) { // 不需要折行,直接输出一个转下一行
- // Console::info("不需要折行,直接输出一个转下一行");
- ++$current_line;
- } else { // 输出很小,写到前面并分片
- // Console::info("输出很小,写到前面并分片");
- $space = intval($max_border / 2) - 2 - strlen($tmp_line);
- $line_data[$current_line] .= str_pad('', $space);
- $line_data[$current_line] .= '| '; // 添加分片
- $line_width[$current_line] -= (strlen($tmp_line) + 3 + $space);
- }
- } else {
- ++$current_line;
- }
- }
+ $keys = array_keys($arr);
+ $values = array_values($arr);
+ $keys[array_search($old_key, $keys)] = $new_key;
+ $arr = array_combine($keys, $values);
}
}
diff --git a/src/ZM/Store/LightCacheInside.php b/src/ZM/Store/LightCacheInside.php
index edd86990..347223c2 100644
--- a/src/ZM/Store/LightCacheInside.php
+++ b/src/ZM/Store/LightCacheInside.php
@@ -21,6 +21,7 @@ class LightCacheInside
self::createTable('connect', 3, 64); // 用于存单机器人模式下的机器人fd的
self::createTable('static_route', 64, 256); // 用于存储
self::createTable('light_array', 8, 512, 0.6);
+ self::createTable('tmp_kv', 3, 512, 0.6);
} catch (ZMException $e) {
return false;
} // 用于存协程等待的状态内容的
diff --git a/src/ZM/Store/Lock/SpinLock.php b/src/ZM/Store/Lock/SpinLock.php
index 5c6664fd..4990507f 100644
--- a/src/ZM/Store/Lock/SpinLock.php
+++ b/src/ZM/Store/Lock/SpinLock.php
@@ -6,8 +6,6 @@ declare(strict_types=1);
namespace ZM\Store\Lock;
-use Swoole\Coroutine;
-use Swoole\Coroutine\System;
use Swoole\Table;
class SpinLock
@@ -28,11 +26,7 @@ class SpinLock
public static function lock(string $key)
{
while (($r = self::$kv_lock->incr($key, 'lock_num')) > 1) { // 此资源已经被锁上了
- if (Coroutine::getCid() != -1) {
- System::sleep(self::$delay / 1000);
- } else {
- usleep(self::$delay * 1000);
- }
+ usleep(self::$delay * 1000);
}
}
diff --git a/src/ZM/Utils/CoMessage.php b/src/ZM/Utils/CoMessage.php
index 1199f6ba..42560000 100644
--- a/src/ZM/Utils/CoMessage.php
+++ b/src/ZM/Utils/CoMessage.php
@@ -6,6 +6,7 @@ namespace ZM\Utils;
use Exception;
use Swoole\Coroutine;
+use Swoole\Timer;
use ZM\Store\LightCacheInside;
use ZM\Store\Lock\SpinLock;
use ZM\Store\ZMAtomic;
@@ -19,7 +20,7 @@ class CoMessage
public static function yieldByWS(array $hang, array $compare, int $timeout = 600)
{
$cid = Coroutine::getuid();
- $api_id = ZMAtomic::get('wait_msg_id')->add(1);
+ $api_id = ZMAtomic::get('wait_msg_id')->add();
$hang['compare'] = $compare;
$hang['coroutine'] = $cid;
$hang['worker_id'] = server()->worker_id;
@@ -42,7 +43,7 @@ class CoMessage
unset($sess[$api_id]);
LightCacheInside::set('wait_api', 'wait_api', $sess);
SpinLock::unlock('wait_api');
- swoole_timer_clear($id);
+ Timer::clear($id);
if ($result === null) {
return false;
}
diff --git a/src/ZM/Utils/Manager/ProcessManager.php b/src/ZM/Utils/Manager/ProcessManager.php
index 143e5109..727850b1 100644
--- a/src/ZM/Utils/Manager/ProcessManager.php
+++ b/src/ZM/Utils/Manager/ProcessManager.php
@@ -7,6 +7,8 @@ declare(strict_types=1);
namespace ZM\Utils\Manager;
use Swoole\Process;
+use ZM\Exception\ZMKnownException;
+use ZM\Utils\DataProvider;
class ProcessManager
{
@@ -22,4 +24,152 @@ class ProcessManager
{
return self::$user_process[$string] ?? null;
}
+
+ /**
+ * @param null|int|string $id_or_name
+ * @throws ZMKnownException
+ * @internal
+ */
+ public static function removeProcessState(int $type, $id_or_name = null)
+ {
+ switch ($type) {
+ case ZM_PROCESS_MASTER:
+ $file = _zm_pid_dir() . '/master.json';
+ if (file_exists($file)) {
+ unlink($file);
+ }
+ return;
+ case ZM_PROCESS_MANAGER:
+ $file = _zm_pid_dir() . '/manager.pid';
+ if (file_exists($file)) {
+ unlink($file);
+ }
+ return;
+ case ZM_PROCESS_WORKER:
+ if (!is_int($id_or_name)) {
+ throw new ZMKnownException('E99999', 'worker_id必须为整数');
+ }
+ $file = _zm_pid_dir() . '/worker.' . $id_or_name . '.pid';
+ if (file_exists($file)) {
+ unlink($file);
+ }
+ return;
+ case ZM_PROCESS_USER:
+ if (!is_string($id_or_name)) {
+ throw new ZMKnownException('E99999', 'process_name必须为字符串');
+ }
+ $file = _zm_pid_dir() . '/user.' . $id_or_name . '.pid';
+ if (file_exists($file)) {
+ unlink($file);
+ }
+ return;
+ case ZM_PROCESS_TASKWORKER:
+ if (!is_int($id_or_name)) {
+ throw new ZMKnownException('E99999', 'worker_id必须为整数');
+ }
+ $file = _zm_pid_dir() . '/taskworker.' . $id_or_name . '.pid';
+ if (file_exists($file)) {
+ unlink($file);
+ }
+ return;
+ }
+ }
+
+ /**
+ * 用于框架内部获取多进程运行状态的函数
+ *
+ * @param mixed $id_or_name
+ * @throws ZMKnownException
+ * @return false|int|mixed
+ * @internal
+ */
+ public static function getProcessState(int $type, $id_or_name = null)
+ {
+ $file = _zm_pid_dir();
+ switch ($type) {
+ case ZM_PROCESS_MASTER:
+ if (!file_exists($file . '/master.json')) {
+ return false;
+ }
+ $json = json_decode(file_get_contents($file . '/master.json'), true);
+ if ($json !== null) {
+ return $json;
+ }
+ return false;
+ case ZM_PROCESS_MANAGER:
+ if (!file_exists($file . '/manager.pid')) {
+ return false;
+ }
+ return intval(file_get_contents($file . '/manager.pid'));
+ case ZM_PROCESS_WORKER:
+ if (!is_int($id_or_name)) {
+ throw new ZMKnownException('E99999', 'worker_id必须为整数');
+ }
+ if (!file_exists($file . '/worker.' . $id_or_name . '.pid')) {
+ return false;
+ }
+ return intval(file_get_contents($file . '/worker.' . $id_or_name . '.pid'));
+ case ZM_PROCESS_USER:
+ if (!is_string($id_or_name)) {
+ throw new ZMKnownException('E99999', 'process_name必须为字符串');
+ }
+ if (!file_exists($file . '/user.' . $id_or_name . '.pid')) {
+ return false;
+ }
+ return intval(file_get_contents($file . '/user.' . $id_or_name . '.pid'));
+ case ZM_PROCESS_TASKWORKER:
+ if (!is_int($id_or_name)) {
+ throw new ZMKnownException('E99999', 'worker_id必须为整数');
+ }
+ if (!file_exists($file . '/taskworker.' . $id_or_name . '.pid')) {
+ return false;
+ }
+ return intval(file_get_contents($file . '/taskworker.' . $id_or_name . '.pid'));
+ default:
+ return false;
+ }
+ }
+
+ /**
+ * 将各进程的pid写入文件,以备后续崩溃及僵尸进程处理使用
+ *
+ * @param int|string $pid
+ * @internal
+ */
+ public static function saveProcessState(int $type, $pid, array $data = [])
+ {
+ switch ($type) {
+ case ZM_PROCESS_MASTER:
+ $file = _zm_pid_dir() . '/master.json';
+ $json = [
+ 'pid' => intval($pid),
+ 'stdout' => $data['stdout'],
+ 'daemon' => $data['daemon'],
+ ];
+ file_put_contents($file, json_encode($json, JSON_UNESCAPED_UNICODE));
+ return;
+ case ZM_PROCESS_MANAGER:
+ $file = _zm_pid_dir() . '/manager.pid';
+ file_put_contents($file, strval($pid));
+ return;
+ case ZM_PROCESS_WORKER:
+ $file = _zm_pid_dir() . '/worker.' . $data['worker_id'] . '.pid';
+ file_put_contents($file, strval($pid));
+ return;
+ case ZM_PROCESS_USER:
+ $file = _zm_pid_dir() . '/user.' . $data['process_name'] . '.pid';
+ file_put_contents($file, strval($pid));
+ return;
+ case ZM_PROCESS_TASKWORKER:
+ $file = _zm_pid_dir() . '/taskworker.' . $data['worker_id'] . '.pid';
+ file_put_contents($file, strval($pid));
+ return;
+ }
+ }
+
+ public static function isStateEmpty(): bool
+ {
+ $ls = DataProvider::scanDirFiles(_zm_pid_dir(), false, true);
+ return empty($ls);
+ }
}
diff --git a/src/ZM/ZMServer.php b/src/ZM/ZMServer.php
index cbc1203f..0df2a012 100644
--- a/src/ZM/ZMServer.php
+++ b/src/ZM/ZMServer.php
@@ -4,7 +4,7 @@ declare(strict_types=1);
namespace ZM;
-use ZM\Command\RunServerCommand;
+use ZM\Command\Server\ServerStartCommand;
use ZM\Console\Console;
use ZM\Event\EventManager;
use ZM\Exception\InitException;
@@ -59,11 +59,11 @@ class ZMServer
define('SOURCE_ROOT_DIR', WORKING_DIR);
define('LOAD_MODE', is_dir(SOURCE_ROOT_DIR . '/src/ZM') ? 0 : 1);
define('FRAMEWORK_ROOT_DIR', realpath(__DIR__ . '/../../'));
- define('ZM_VERSION_ID', ConsoleApplication::VERSION_ID);
- define('ZM_VERSION', ConsoleApplication::VERSION);
+ define('ZM_VERSION_ID', Framework::VERSION_ID);
+ define('ZM_VERSION', Framework::VERSION);
$options = array_map(function ($x) {
return $x->getDefault();
- }, RunServerCommand::exportDefinition()->getOptions());
+ }, ServerStartCommand::exportDefinition()->getOptions());
(new Framework($options, true))->start();
}
diff --git a/src/ZM/global_functions.php b/src/ZM/global_functions.php
index ae5504a7..ae23087f 100644
--- a/src/ZM/global_functions.php
+++ b/src/ZM/global_functions.php
@@ -46,7 +46,7 @@ function get_class_path(string $class_name): ?string
*/
function _zm_env_check()
{
- if (!extension_loaded('swoole')) {
+ if (!extension_loaded('swoole') && !extension_loaded('openswoole')) {
exit(zm_internal_errcode('E00001') . "Can not find swoole extension.\n");
}
if (version_compare(SWOOLE_VERSION, '4.5.0') === -1) {
diff --git a/zhamao b/zhamao
index f8581dbd..c3eb7aaf 100755
--- a/zhamao
+++ b/zhamao
@@ -5,8 +5,10 @@
# author: crazywhalecc
# since: 2.5.0
-
-if [ -f "$(pwd)/runtime/php" ]; then
+if [ "$ZM_CUSTOM_PHP_PATH" != "" ]; then
+ echo "* Using PHP executable: ""$ZM_CUSTOM_PHP_PATH"
+ executable="$ZM_CUSTOM_PHP_PATH"
+elif [ -f "$(pwd)/runtime/php" ]; then
executable="$(pwd)/runtime/php"
echo "* Framework started with built-in php."
else