Files
shop-platform/src/ws_server.php

269 lines
8.8 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
// WebSocket服务器启动脚本
// 使用方法php ws_server.php
// 启用错误报告
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
require __DIR__ . '/vendor/autoload.php';
// 初始化ThinkPHP应用环境加载配置和环境变量主要用于数据库连接和其他配置
use think\App;
// 创建应用实例
// @intelephense-ignore-next-line
$app = new App();
// 加载环境变量
if (is_file(__DIR__ . '/.env')) {
$app->env->load(__DIR__ . '/.env');
}
// 根据APP_ENV加载环境特定的.env文件
$appEnv = getenv('APP_ENV') ?: '';
if ($appEnv) {
$envFile = __DIR__ . '/.env.' . $appEnv;
if (is_file($envFile)) {
$app->env->load($envFile);
}
}
use Ratchet\App as RatchetApp;
use Ratchet\ConnectionInterface;
use Ratchet\MessageComponentInterface;
// 配置WebSocket服务器
$httpHost = 'localhost'; // 客户端连接时使用的主机名
$port = getenv('WS_PORT') ?: 8080; // WebSocket服务器端口
$address = '0.0.0.0'; // 监听所有网络接口
// 创建WebSocket服务器应用 - 参数顺序httpHost, port, address
$ratchetApp = new RatchetApp($httpHost, $port, $address);
// 获取所有addon与InitAddon.php逻辑保持一致
// 1. 从数据库获取插件列表
use app\model\system\Addon;
$addonDir = __DIR__ . '/addon';
$addonNames = [];
// 从数据库获取addon列表
try {
$addon_model = new Addon();
$addon_data = $addon_model->getAddonList([], 'name,status');
$current_addons = $addon_data['data'];
$db_addon_names = array_column($current_addons, 'name');
// 2. 从addon目录读取插件列表
$dir_addon_names = [];
if (is_dir($addonDir)) {
$dir_handle = opendir($addonDir);
if ($dir_handle) {
while (($file = readdir($dir_handle)) !== false) {
if ($file != '.' && $file != '..' && is_dir($addonDir . '/' . $file)) {
$dir_addon_names[] = $file;
}
}
closedir($dir_handle);
}
}
// 3. 使用数据库中的插件列表进行后续处理
$current_addon_names = $db_addon_names;
// 4. 记录已启用的插件
$enabled_addons = [];
foreach ($current_addons as $addon) {
if (isset($addon['status']) && $addon['status'] == 1) {
$enabled_addons[] = $addon['name'];
}
}
echo "[WebSocket服务器] 从数据库获取的插件列表: " . implode(', ', $current_addon_names) . "\n";
echo "[WebSocket服务器] 已启用的插件: " . implode(', ', $enabled_addons) . "\n";
echo "[WebSocket服务器] 目录中存在的插件: " . implode(', ', $dir_addon_names) . "\n";
// 5. 比较数据库和目录插件列表的差异
$db_only_addons = array_diff($db_addon_names, $dir_addon_names);
$dir_only_addons = array_diff($dir_addon_names, $db_addon_names);
if (!empty($db_only_addons)) {
echo "[WebSocket服务器] 数据库中存在但目录中不存在的插件: " . implode(', ', $db_only_addons) . "\n";
}
if (!empty($dir_only_addons)) {
echo "[WebSocket服务器] 目录中存在但数据库中不存在的插件: " . implode(', ', $dir_only_addons) . "\n";
}
} catch (\Exception $e) {
echo "[WebSocket服务器] 获取插件列表失败: " . $e->getMessage() . "\n";
echo "[WebSocket服务器] 回退到直接扫描目录获取插件列表\n";
// 回退到直接扫描目录
$addonNames = [];
if (is_dir($addonDir)) {
$handle = opendir($addonDir);
while (($file = readdir($handle)) !== false) {
if ($file != '.' && $file != '..' && is_dir($addonDir . '/' . $file)) {
$addonNames[] = $file;
}
}
closedir($handle);
sort($addonNames);
}
$current_addon_names = $addonNames;
$enabled_addons = $addonNames; // 回退模式下默认所有插件都启用
}
// 为每个addon注册WebSocket控制器并记录注册情况
$registeredAddons = [];
$unregisteredAddons = [];
$disabledAddons = [];
$missingDirAddons = [];
foreach ($current_addon_names as $addonName) {
// 检查插件是否已启用
if (!in_array($addonName, $enabled_addons)) {
echo "[{$addonName}] 插件未启用跳过WebSocket控制器注册\n";
$disabledAddons[] = $addonName;
continue;
}
// 检查插件目录是否存在
if (!is_dir($addonDir . '/' . $addonName)) {
echo "[{$addonName}] 插件目录不存在跳过WebSocket控制器注册\n";
$missingDirAddons[] = $addonName;
continue;
}
$webSocketClass = "addon\\{$addonName}\\api\\controller\\WebSocket";
// 检查WebSocket控制器是否存在
try {
if (class_exists($webSocketClass)) {
// 注册到/ws/{addonName}路径
$path = '/ws/' . $addonName;
$ratchetApp->route($path, new $webSocketClass(), array('*'));
echo "已注册WebSocket控制器{$webSocketClass} 到路径 {$path}\n";
$registeredAddons[] = $addonName;
} else {
echo "[{$addonName}] WebSocket控制器不存在 ({$webSocketClass})\n";
$unregisteredAddons[] = $addonName;
}
} catch (\Exception $e) {
echo "[{$addonName}] 检查WebSocket控制器时出错{$e->getMessage()}\n";
$unregisteredAddons[] = $addonName;
}
}
// 实现默认的/ws路径的简单测试控制器
class DefaultWebSocketController implements MessageComponentInterface
{
protected $clients;
public function __construct()
{
$this->clients = new \SplObjectStorage;
}
public function onOpen(ConnectionInterface $conn)
{
$this->clients->attach($conn);
echo "[默认路径] New connection! ({$conn->resourceId})\n";
$conn->send(json_encode([
'type' => 'welcome',
'message' => '欢迎连接到默认WebSocket测试路径',
'info' => '此路径仅用于测试,不提供实际功能。请使用/ws/{addonName}连接到具体的addon服务。'
]));
}
public function onMessage(ConnectionInterface $conn, $msg)
{
echo "[默认路径] Received message from {$conn->resourceId}: $msg\n";
try {
$data = json_decode($msg, true);
if (isset($data['action']) && $data['action'] === 'ping') {
$conn->send(json_encode(['type' => 'pong']));
} else {
$conn->send(json_encode([
'type' => 'info',
'message' => '收到消息,但默认路径不提供实际功能',
'received' => $data
]));
}
} catch (\Exception $e) {
$conn->send(json_encode(['type' => 'error', 'message' => '解析消息失败: ' . $e->getMessage()]));
}
}
public function onClose(ConnectionInterface $conn)
{
$this->clients->detach($conn);
echo "[默认路径] Connection {$conn->resourceId} has disconnected\n";
}
public function onError(ConnectionInterface $conn, \Exception $e)
{
echo "[默认路径] An error has occurred: {$e->getMessage()}\n";
$conn->close();
}
}
// 注册默认的/ws路径测试控制器
$ratchetApp->route('/ws', new DefaultWebSocketController(), array('*'));
echo "已注册默认WebSocket测试控制器到路径 /ws\n";
echo "WebSocket服务器已启动监听地址: ws://{$httpHost}:{$port}\n";
// 显示已注册WebSocket控制器的addon路径
echo "\n已注册WebSocket控制器的addon路径\n";
if (!empty($registeredAddons)) {
foreach ($registeredAddons as $addonName) {
echo " - ws://{$httpHost}:{$port}/ws/{$addonName} (已注册)\n";
}
} else {
echo " - 暂无已注册的WebSocket控制器\n";
}
// 显示未注册WebSocket控制器的addon路径
echo "\n未注册WebSocket控制器的addon路径\n";
if (!empty($unregisteredAddons)) {
foreach ($unregisteredAddons as $addonName) {
echo " - ws://{$httpHost}:{$port}/ws/{$addonName} (未注册)\n";
}
} else {
echo " - 所有已启用且目录存在的addon都已注册WebSocket控制器\n";
}
// 显示未启用的addon
echo "\n未启用的addon\n";
if (!empty($disabledAddons)) {
foreach ($disabledAddons as $addonName) {
echo " - {$addonName} (未启用)\n";
}
} else {
echo " - 所有addon都已启用\n";
}
// 显示目录不存在的addon
echo "\n目录不存在的addon\n";
if (!empty($missingDirAddons)) {
foreach ($missingDirAddons as $addonName) {
echo " - {$addonName} (目录不存在)\n";
}
} else {
echo " - 所有已启用的addon目录都存在\n";
}
echo "\n默认测试路径:\n";
echo " - ws://{$httpHost}:{$port}/ws (默认路径,用于连接测试)\n";
echo "按 Ctrl+C 停止服务器\n";
// 运行服务器
$ratchetApp->run();