init
- 框架初始化 - 安装插件 - 修复PHP8.4报错
This commit is contained in:
68
addons/shopro/console/Command.php
Normal file
68
addons/shopro/console/Command.php
Normal file
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
namespace addons\shopro\console;
|
||||
|
||||
use think\console\Input;
|
||||
use think\console\Output;
|
||||
use think\console\Command as BaseCommand;
|
||||
|
||||
|
||||
class Command extends BaseCommand
|
||||
{
|
||||
protected $input = null;
|
||||
protected $output = null;
|
||||
protected $commonCb = null;
|
||||
|
||||
/**
|
||||
* 执行帮助命令
|
||||
*/
|
||||
protected function execute(Input $input, Output $output)
|
||||
{
|
||||
$this->input = $input;
|
||||
$this->output = $output;
|
||||
|
||||
if ($this->commonCb && $this->commonCb instanceof \Closure) {
|
||||
($this->commonCb)($input, $output);
|
||||
}
|
||||
|
||||
$code = $input->getArgument('code');
|
||||
$code = $code ?: '1';
|
||||
|
||||
$this->choose($code);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 选择要执行的命令
|
||||
*/
|
||||
public function choose($code)
|
||||
{
|
||||
$commands = $this->commands;
|
||||
$codes = array_column($commands, 'code');
|
||||
$names = array_column($commands, 'name');
|
||||
|
||||
if (!in_array($code, $codes) && !in_array($code, $names)) {
|
||||
$this->output->writeln("已取消");
|
||||
return true;
|
||||
}
|
||||
|
||||
$commands = array_column($commands, null, 'code');
|
||||
$name = isset($commands[$code]) ? $commands[$code]['name'] : $code;
|
||||
$name = \think\helper\Str::camel($name);
|
||||
if (method_exists($this, $name)) {
|
||||
$this->{$name}();
|
||||
} else {
|
||||
$this->cancel();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 取消操作
|
||||
*/
|
||||
public function cancel()
|
||||
{
|
||||
$this->output->writeln("已取消");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
174
addons/shopro/console/ShoproChat.php
Normal file
174
addons/shopro/console/ShoproChat.php
Normal file
@@ -0,0 +1,174 @@
|
||||
<?php
|
||||
|
||||
namespace addons\shopro\console;
|
||||
|
||||
use think\console\Input;
|
||||
use think\console\Output;
|
||||
use think\console\input\Argument;
|
||||
use think\console\input\Option;
|
||||
use think\exception\HttpResponseException;
|
||||
use Workerman\Worker;
|
||||
use Workerman\Timer;
|
||||
use PHPSocketIO\SocketIO;
|
||||
use Workerman\Protocols\Http\Request;
|
||||
use Workerman\Connection\TcpConnection;
|
||||
use addons\shopro\library\chat\Chat;
|
||||
use addons\shopro\library\chat\Getter;
|
||||
use addons\shopro\library\chat\Sender;
|
||||
use addons\shopro\library\chat\traits\Helper;
|
||||
use think\Db;
|
||||
|
||||
class ShoproChat extends Command
|
||||
{
|
||||
use Helper;
|
||||
|
||||
protected $input = null;
|
||||
protected $output = null;
|
||||
|
||||
/**
|
||||
* 帮助命令配置
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('shopro:chat')
|
||||
->addArgument('action', Argument::OPTIONAL, "action start|stop|restart|status", 'start')
|
||||
->addArgument('type', Argument::OPTIONAL, "d -d")
|
||||
->addOption('debug', null, Option::VALUE_OPTIONAL, '开启调试模式', false)
|
||||
->setHelp('此命令是用来启动 Shopro商城 的客服服务端进程')
|
||||
->setDescription('Shopro商城 客服');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 执行帮助命令
|
||||
*/
|
||||
protected function execute(Input $input, Output $output)
|
||||
{
|
||||
$this->input = $input;
|
||||
$this->output = $output;
|
||||
|
||||
global $argv;
|
||||
|
||||
$action = $input->getArgument('action');
|
||||
$type = $input->getArgument('type') ? '-d' : '';
|
||||
$debug = $input->hasOption('debug');
|
||||
|
||||
if (strpos(strtolower(PHP_OS), 'win') === false) {
|
||||
// windows 不需要设置参数
|
||||
|
||||
$argv = [];
|
||||
$argv[0] = 'think shopro:chat';
|
||||
$argv[1] = $action;
|
||||
$argv[2] = $type ? '-d' : '';
|
||||
}
|
||||
|
||||
$this->start($input, $output, $debug);
|
||||
}
|
||||
|
||||
|
||||
private function start($input, $output, $debug)
|
||||
{
|
||||
$chatSystem = $this->getConfig('system');
|
||||
$ssl = $chatSystem['ssl'] ?? 'none';
|
||||
$ssl_cert = $chatSystem['ssl_cert'] ?? '';
|
||||
$ssl_key = $chatSystem['ssl_key'] ?? '';
|
||||
$worker_num = $chatSystem['worker_num'] ?? 1;
|
||||
$port = $chatSystem['port'] ?? '';
|
||||
$port = $port ? intval($port) : 2121;
|
||||
$inside_host = $chatSystem['inside_host'] ?? '';
|
||||
$inside_host = '0.0.0.0'; // 这里默认都只绑定 0.0.0.0
|
||||
$inside_port = $chatSystem['inside_port'] ?? '';
|
||||
$inside_port = $inside_port ? intval($inside_port) : 9191;
|
||||
|
||||
// 创建socket.io服务端
|
||||
$context = [
|
||||
// 'pingInterval' => '10', // 参数不可用
|
||||
// 'pingTimeout' => '50' // 参数不对,不可用
|
||||
];
|
||||
if ($ssl == 'cert') {
|
||||
// 证书模式
|
||||
$context['ssl'] = [
|
||||
'local_cert' => $ssl_cert,
|
||||
'local_pk' => $ssl_key,
|
||||
'verify_peer' => false
|
||||
];
|
||||
}
|
||||
|
||||
$io = new SocketIO($port, $context);
|
||||
$io->worker->name = 'ShoproChatWorker';
|
||||
// $io->worker->count = $worker_num; // 启动 worker 的进程数量,经测试 linux 上不支持设置多个进程, 再启动 web-msg-sender 时候 会导致多次启动同一个端口,端口被占用的情况
|
||||
$io->debug = $debug; // 自定义 debug
|
||||
|
||||
// 定义命名空间
|
||||
$nsp = $io->of('/chat');
|
||||
$io->on('workerStart', function () use ($io, $nsp, $inside_host, $inside_port) {
|
||||
$inner_http_worker = new Worker('http://' . $inside_host . ':' . $inside_port);
|
||||
$inner_http_worker->onMessage = function (TcpConnection $httpConnection, Request $request) use ($io, $nsp) {
|
||||
// 请求地址
|
||||
$uri = $request->uri();
|
||||
// 请求参数
|
||||
$data = $request->post();
|
||||
|
||||
$chat = new Chat($io, $nsp);
|
||||
$chat->innerWorker($httpConnection, $uri, $data);
|
||||
};
|
||||
$inner_http_worker->listen();
|
||||
|
||||
|
||||
// 添加排队等待定时器 【30 秒 通知一次等待中的用户,有等待中用户被接入时也会主动通知等待中用户】
|
||||
$getter = new Getter(null, $io, $nsp);
|
||||
$sender = new Sender(null, $io, $nsp, $getter);
|
||||
Timer::add(30, function () use ($getter, $sender) {
|
||||
// 定时通知所有房间中排队用户排名变化
|
||||
$sender->allWaitingQueue();
|
||||
});
|
||||
|
||||
|
||||
Timer::add(15, function () use ($getter) {
|
||||
// 更新客服忙碌度
|
||||
$getter->updateCustomerServiceBusyPercent();
|
||||
});
|
||||
});
|
||||
|
||||
// 当有客户端连接时打印一行文字
|
||||
$nsp->on('connection', function($socket) use ($io) {
|
||||
$nsp = $io->of('/chat');
|
||||
// 连接时候只走一次,后续发消息,这个方法就不走了
|
||||
|
||||
// 绑定客服连接事件
|
||||
try {
|
||||
$chat = new Chat($io, $nsp, $socket);
|
||||
|
||||
$chat->on();
|
||||
} catch (HttpResponseException $e) {
|
||||
$data = $e->getResponse()->getData();
|
||||
$message = $data ? ($data['msg'] ?? '') : $e->getMessage();
|
||||
echo $message;
|
||||
} catch (\Exception $e) {
|
||||
echo $e->getMessage();
|
||||
}
|
||||
});
|
||||
|
||||
// 定义第二个命名空间
|
||||
// $nsp = $io->of('/server');
|
||||
// $nsp->on('connection', function($socket) use ($io) {
|
||||
|
||||
// // $chat = new Chat($io, $socket);
|
||||
|
||||
// // $chat->on();
|
||||
// echo "new connection server\n";
|
||||
// });
|
||||
|
||||
// 断开 mysql 连接,防止 2006 MySQL server has gone away 错误
|
||||
Db::close();
|
||||
|
||||
// 日志文件
|
||||
if (!is_dir(RUNTIME_PATH . 'log/chat')) {
|
||||
@mkdir(RUNTIME_PATH . 'log/chat', 0755, true);
|
||||
}
|
||||
Worker::$logFile = RUNTIME_PATH . 'log/chat/shopro_chat.log';
|
||||
Worker::$stdoutFile = RUNTIME_PATH . 'log/chat/std_out.log'; // 如果部署的时候部署错误(比如未删除php禁用函数),会产生大量日志,先关掉
|
||||
|
||||
Worker::runAll();
|
||||
}
|
||||
}
|
||||
218
addons/shopro/console/ShoproHelp.php
Normal file
218
addons/shopro/console/ShoproHelp.php
Normal file
@@ -0,0 +1,218 @@
|
||||
<?php
|
||||
|
||||
namespace addons\shopro\console;
|
||||
|
||||
use think\Db;
|
||||
use Exception;
|
||||
use think\console\input\Argument;
|
||||
use think\console\input\Option;
|
||||
use app\admin\model\shopro\Admin;
|
||||
use think\Queue;
|
||||
|
||||
class ShoproHelp extends Command
|
||||
{
|
||||
protected $input = null;
|
||||
protected $output = null;
|
||||
|
||||
/**
|
||||
* 支持的命令列表
|
||||
*/
|
||||
protected $commands = [
|
||||
['code' => "0", 'name' => 'cancel', 'desc' => '取消'],
|
||||
['code' => "1", 'name' => 'all', 'desc' => 'shopro 帮助工具列表'],
|
||||
|
||||
// ['code' => "2", 'name' => 'open_debug', 'desc' => '开启 debug'],
|
||||
// ['code' => "3", 'name' => 'close_debug', 'desc' => '关闭 debug'],
|
||||
['code' => "4", 'name' => 'admin_reset_password', 'desc' => '重置管理员密码'],
|
||||
['code' => "5", 'name' => 'admin_clear_login_fail', 'desc' => '清除管理员登录锁定状态'],
|
||||
// ['code' => "6", 'name' => 'database_notes_md', 'desc' => '生成 markdown 格式的数据库字典'],
|
||||
// ['code' => "7", 'name' => 'database_notes_pdf', 'desc' => '生成 pdf 格式的数据库字典'],
|
||||
// ['code' => "8", 'name' => 'update_composer', 'desc' => '更新 composer 包'],
|
||||
['code' => "9", 'name' => 'queue', 'desc' => '检查队列状态'],
|
||||
// ['code' => "10", 'name' => 'clear_cache', 'desc' => '清空缓存']
|
||||
];
|
||||
|
||||
/**
|
||||
* 帮助命令配置
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('shopro:help')
|
||||
->addArgument('code', Argument::OPTIONAL, "请输入操作编号")
|
||||
->setDescription('shopro 帮助命令');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 全部命令集合
|
||||
*/
|
||||
public function all()
|
||||
{
|
||||
$this->output->newLine();
|
||||
$this->output->writeln("shopro 帮助命令行");
|
||||
$this->output->writeln('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~');
|
||||
$this->output->newLine();
|
||||
|
||||
if (!is_dir(RUNTIME_PATH . 'storage')) {
|
||||
@mkdir(RUNTIME_PATH . 'storage', 0755, true);
|
||||
}
|
||||
|
||||
foreach ($this->commands as $command) {
|
||||
$this->output->writeln("[" . $command['code'] . "] " . $command['desc']);
|
||||
}
|
||||
|
||||
$this->output->newLine();
|
||||
|
||||
$code = $this->output->ask(
|
||||
$this->input,
|
||||
'请输入命令代号',
|
||||
'0'
|
||||
);
|
||||
|
||||
$this->choose($code);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 打开调试模式
|
||||
*/
|
||||
// public function openDebug()
|
||||
// {
|
||||
// $this->setEnvFilePath();
|
||||
|
||||
// $this->setEnvVar('APP_DEBUG', 'true');
|
||||
|
||||
// $this->output->writeln("debug 开启成功");
|
||||
// return true;
|
||||
// }
|
||||
|
||||
|
||||
// /**
|
||||
// * 关闭调试模式
|
||||
// */
|
||||
// public function closeDebug()
|
||||
// {
|
||||
// $this->setEnvFilePath();
|
||||
|
||||
// $this->setEnvVar('APP_DEBUG', 'false');
|
||||
|
||||
// $this->output->writeln("debug 关闭成功");
|
||||
// return true;
|
||||
// }
|
||||
|
||||
|
||||
/**
|
||||
* 重置管理员密码
|
||||
*/
|
||||
public function adminResetPassword()
|
||||
{
|
||||
$this->output->newLine();
|
||||
$this->output->writeln("重置管理员密码");
|
||||
$this->output->writeln('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~');
|
||||
$this->output->newLine();
|
||||
|
||||
$username = $this->output->ask(
|
||||
$this->input,
|
||||
'请输入要重置的管理员账号'
|
||||
);
|
||||
|
||||
$admin = null;
|
||||
if ($username) {
|
||||
$admin = Admin::where('username', $username)->find();
|
||||
}
|
||||
|
||||
if (!$admin) {
|
||||
$this->output->error("请输入正确的管理员账号");
|
||||
return false;
|
||||
}
|
||||
|
||||
$password = $this->output->ask(
|
||||
$this->input,
|
||||
'请输入要设置的密码[6-16]'
|
||||
);
|
||||
|
||||
if (empty($password) || strlen($password) < 6 || strlen($password) > 16) {
|
||||
$this->output->error("请输入正确的密码");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 重置密码
|
||||
$admin->salt = $admin->salt ?: mt_rand(1000, 9999);
|
||||
$admin->password = md5(md5($password) . $admin->salt);
|
||||
$admin->save();
|
||||
|
||||
$this->output->writeln("账号 [" . $admin->username . "] 的密码重置成功");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 清除管理员登录失败锁定状态
|
||||
*/
|
||||
public function adminClearLoginFail()
|
||||
{
|
||||
$this->output->newLine();
|
||||
$this->output->writeln("清除管理员登录锁定状态");
|
||||
$this->output->writeln('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~');
|
||||
$this->output->newLine();
|
||||
|
||||
$username = $this->output->ask(
|
||||
$this->input,
|
||||
'请输入要清除的管理员账号'
|
||||
);
|
||||
|
||||
$admin = null;
|
||||
if ($username) {
|
||||
$admin = Admin::where('username', $username)->find();
|
||||
}
|
||||
|
||||
if (!$admin) {
|
||||
$this->output->error("请输入正确的管理员账号");
|
||||
return false;
|
||||
}
|
||||
|
||||
$admin->loginfailure = 0;
|
||||
$admin->save();
|
||||
|
||||
$this->output->writeln("账号 [" . $admin->username . "] 锁定状态清除成功");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 检查队列状态
|
||||
*/
|
||||
public function queue()
|
||||
{
|
||||
@unlink(RUNTIME_PATH . 'storage/queue/shopro.log');
|
||||
@unlink(RUNTIME_PATH . 'storage/queue/shopro-high.log');
|
||||
|
||||
$queue = config('queue');
|
||||
$connector = $queue['connector'] ?? 'sync';
|
||||
|
||||
if ($connector == 'sync') {
|
||||
$this->output->error("队列驱动不可以使用 sync,请选择 database 或者 redis 配置");
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->output->writeln('当前队列驱动为:' . $connector);
|
||||
$this->output->writeln('正在添加测试队列...');
|
||||
$this->output->newLine();
|
||||
|
||||
// 添加验证队列
|
||||
Queue::push('\addons\shopro\job\Test@shopro', [], 'shopro'); // 普通队列
|
||||
Queue::push('\addons\shopro\job\Test@shoproHigh', [], 'shopro-high'); // 高优先级队列
|
||||
|
||||
$this->output->writeln('测试队列添加成功');
|
||||
$this->output->writeln('请检查 ' . str_replace('\\', '/', RUNTIME_PATH . 'storage/queue') . '目录下是否存在如下文件,并且文件内容为当前测试的时间');
|
||||
$this->output->newLine();
|
||||
$this->output->writeln(str_replace('\\', '/', RUNTIME_PATH . 'storage/queue') . 'shopro.log // 如果没有该文件,则普通优先级队列未监听');
|
||||
$this->output->writeln(str_replace('\\', '/', RUNTIME_PATH . 'storage/queue') . 'shopro-high.log // 如果没有该文件,则高优先级队列未监听');
|
||||
$this->output->newLine();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user