Files
spacestation/api/core/HD_WS_Controller.php
2025-11-29 10:40:00 +08:00

287 lines
9.0 KiB
PHP

<?php
defined('BASEPATH') or exit('No direct script access allowed');
class HD_WS_Controller extends CI_Controller
{
protected $db_config;
protected $last_connect_time = 0;
protected $reconnect_count = 0;
protected $last_ping_time = 0;
public function __construct()
{
parent::__construct();
$this->output->enable_profiler(FALSE);
$this->loadDatabaseConfig();
// 加载类
$this->load->library('myResponse');
$this->load->library('websocket/wsResponse');
$this->load->library('websocket/validToken');
$this->load->library('websocket/message');
$this->load->model('ws/ws_conn_model');
}
/**
* 手动加载数据库配置
*/
private function loadDatabaseConfig()
{
$config_path = APPPATH . 'config/database.php';
if (file_exists($config_path)) {
include $config_path;
if (isset($db) && is_array($db) && isset($db['default'])) {
$this->db_config = $db['default'];
// 确保使用短连接
$this->db_config['pconnect'] = FALSE;
$this->db_config['db_debug'] = FALSE; // 关闭调试,避免自动输出错误
return;
} else {
echo "[" . date('Y-m-d H:i:s') . "] 找不到数据库default配置\n";
}
} else {
echo "[" . date('Y-m-d H:i:s') . "] 找不到数据库配置文件\n";
}
}
/**
* 获取数据库连接(带自动重连和连接检查)
*/
public function getDbConnection()
{
$now = time();
// 检查现有连接是否有效
if (isset($this->db) && $this->db->conn_id) {
try {
// 定期ping数据库(每30秒一次)
if ($now - $this->last_ping_time > 30) {
$this->db->query('SELECT 1');
$this->last_ping_time = $now;
}
return $this->db;
} catch (Exception $e) {
echo "[" . date('Y-m-d H:i:s') . "] 数据库连接已断开: " . $e->getMessage() . "\n";
// 关闭无效连接
if ($this->db->conn_id) {
try {
$this->db->close();
} catch (Exception $e2) {
// 忽略关闭时的错误
}
}
unset($this->db);
}
}
// 限制重连频率
if ($now - $this->last_connect_time < 2) { // 2秒内只能重连一次
if ($this->reconnect_count > 5) {
throw new Exception('数据库重连过于频繁,请检查数据库状态');
}
}
echo "[" . date('Y-m-d H:i:s') . "] 创建新的数据库连接...\n";
try {
// 创建新连接
$this->db = $this->load->database($this->db_config, TRUE);
if (!$this->db->conn_id) {
throw new Exception('数据库连接失败');
}
// 测试新连接
$this->db->query('SELECT 1');
$this->last_connect_time = $now;
$this->last_ping_time = $now;
$this->reconnect_count++;
echo "[" . date('Y-m-d H:i:s') . "] 数据库连接创建成功\n";
return $this->db;
} catch (Exception $e) {
echo "[" . date('Y-m-d H:i:s') . "] 数据库连接失败: " . $e->getMessage() . "\n";
unset($this->db);
throw $e;
}
}
/**
* 安全的数据库查询(自动重试)
*/
public function safeDbQuery($callback, $max_retry = 3)
{
$retry = 0;
$last_error = '';
while ($retry <= $max_retry) {
try {
$db = $this->getDbConnection();
$result = call_user_func($callback, $db);
// 重置重连计数(成功查询后)
if ($retry == 0) {
$this->reconnect_count = 0;
}
return $result;
} catch (Exception $e) {
$last_error = $e->getMessage();
$retry++;
// 检查是否是连接错误
$is_connection_error = $this->isConnectionError($last_error);
if ($is_connection_error) {
echo "[" . date('Y-m-d H:i:s') . "] 数据库连接错误,重试 {$retry}/{$max_retry}\n";
// 如果是连接错误,强制重置连接
if (isset($this->db) && $this->db->conn_id) {
try {
$this->db->close();
} catch (Exception $e2) {
// 忽略关闭错误
}
unset($this->db);
}
if ($retry > $max_retry) {
throw new Exception('数据库操作失败,重试次数用尽: ' . $last_error);
}
// 等待后重试(递增等待时间)
usleep(100000 * $retry); // 100ms * 重试次数
} else {
// 非连接错误,直接抛出
throw new Exception('数据库查询错误: ' . $last_error);
}
}
}
throw new Exception('数据库操作失败: ' . $last_error);
}
/**
* 判断错误是否为连接错误
*/
private function isConnectionError($error_message)
{
$connection_errors = [
'MySQL server has gone away',
'Lost connection to MySQL server',
'Connection refused',
'Too many connections',
'Query execution was interrupted',
'SSL connection has been closed',
'Error reading result set'
];
foreach ($connection_errors as $error) {
if (stripos($error_message, $error) !== false) {
return true;
}
}
return false;
}
/**
* 记录连接信息
*/
public function recordConnection($fd, $user_id, $platform, $token, $ip)
{
return $this->safeDbQuery(function ($db) use ($fd, $user_id, $platform, $token, $ip) {
// 先清理该用户可能存在的旧连接
$db->where('user_id', $user_id);
$db->where('platform', $platform);
$delete_result = $db->delete('lc_ws_conn');
// if (!$delete_result) {
// // 删除失败不一定是错误,可能记录不存在
// }
// 插入新连接记录
$connection_data = [
'fd' => $fd,
'platform' => $platform,
'user_id' => $user_id,
'token' => $token,
'ip' => $ip,
'connect_time' => date('Y-m-d H:i:s'),
'last_activity' => date('Y-m-d H:i:s'),
'status' => 1
];
$insert_result = $db->replace('lc_ws_conn', $connection_data);
if (!$insert_result) {
throw new Exception('插入连接记录失败');
}
return $db->insert_id();
});
}
/**
* 删除连接记录
*/
public function removeConnection($fd)
{
return $this->safeDbQuery(function ($db) use ($fd) {
$db->where('fd', $fd);
$result = $db->delete('lc_ws_conn');
return $result;
});
}
/**
* 更新最后活动时间
*/
public function updateActivity($fd)
{
return $this->safeDbQuery(function ($db) use ($fd) {
$db->where('fd', $fd);
$result = $db->update('lc_ws_conn', [
'last_activity' => date('Y-m-d H:i:s')
]);
return true;
});
}
/**
* 根据用户ID获取连接FD
*/
public function getConnectionByUserId($platform, $user_id)
{
return $this->safeDbQuery(function ($db) use ($platform, $user_id) {
$db->select('*');
$db->from('lc_ws_conn');
$db->where('platform', $platform);
$db->where('user_id', $user_id);
$db->where('status', 1);
$query = $db->get();
if (!$query) {
throw new Exception('查询失败');
}
if ($query->num_rows() > 0) {
return $query->row();
}
return null;
});
}
/**
* 手动关闭数据库连接
*/
public function closeDbConnection()
{
if (isset($this->db) && $this->db->conn_id) {
try {
$this->db->close();
echo "[" . date('Y-m-d H:i:s') . "] 数据库连接已关闭\n";
} catch (Exception $e) {
echo "[" . date('Y-m-d H:i:s') . "] 关闭数据库连接时出错: " . $e->getMessage() . "\n";
}
unset($this->db);
}
}
}