From 0c70613865678f0abcaf94a2ab2cf5c8ddc987e6 Mon Sep 17 00:00:00 2001 From: kuaifan Date: Mon, 11 Nov 2024 22:44:18 +0800 Subject: [PATCH] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E5=88=9D=E5=A7=8B?= =?UTF-8?q?=E5=8C=96=E6=95=B0=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Events/ServerStartEvent.php | 27 -- app/Events/WorkerStartEvent.php | 22 +- app/Http/Controllers/Api/UsersController.php | 253 +++++++++---------- app/Http/Middleware/WebApi.php | 19 +- app/Models/User.php | 17 +- app/Models/UserBot.php | 2 +- app/Module/Base.php | 71 +++--- app/Module/Table/AbstractData.php | 86 +++++++ app/Module/Table/GlobalData.php | 7 + app/Module/Table/OnlineData.php | 22 ++ app/Services/RequestContext.php | 142 +++++++++++ app/Tasks/WebSocketDialogMsgTask.php | 7 +- config/laravels.php | 34 ++- 13 files changed, 487 insertions(+), 222 deletions(-) delete mode 100644 app/Events/ServerStartEvent.php create mode 100644 app/Module/Table/AbstractData.php create mode 100644 app/Module/Table/GlobalData.php create mode 100644 app/Module/Table/OnlineData.php create mode 100644 app/Services/RequestContext.php diff --git a/app/Events/ServerStartEvent.php b/app/Events/ServerStartEvent.php deleted file mode 100644 index 92702c959..000000000 --- a/app/Events/ServerStartEvent.php +++ /dev/null @@ -1,27 +0,0 @@ -startMsecTime = $this->msecTime(); - } - - private function msecTime() - { - list($msec, $sec) = explode(' ', microtime()); - $time = explode(".", $sec . ($msec * 1000)); - return $time[0]; - } -} diff --git a/app/Events/WorkerStartEvent.php b/app/Events/WorkerStartEvent.php index 9a034e2f4..feb4dddb4 100644 --- a/app/Events/WorkerStartEvent.php +++ b/app/Events/WorkerStartEvent.php @@ -17,14 +17,20 @@ class WorkerStartEvent implements WorkerStartInterface public function handle(Server $server, $workerId) { - if (isset($server->startMsecTime) && Cache::get("swooleServerStartMsecTime") != $server->startMsecTime) { - Cache::forever("swooleServerStartMsecTime", $server->startMsecTime); - WebSocket::query()->delete(); - // - $all = Base::json2array(Cache::get("User::online:all")); - foreach ($all as $userid) { - Cache::forget("User::online:" . $userid); - } + // 仅在Worker进程启动时执行一次初始化代码 + $initTable = app('swoole')->initFlagTable; + if ($initTable->incr('init_flag', 'value') === 1) { + $this->handleFirstWorkerTasks(); + } + } + + private function handleFirstWorkerTasks() + { + WebSocket::query()->delete(); + // + $all = Base::json2array(Cache::get("User::online:all")); + foreach ($all as $userid) { + Cache::forget("User::online:" . $userid); } } } diff --git a/app/Http/Controllers/Api/UsersController.php b/app/Http/Controllers/Api/UsersController.php index 307e758c4..0890e804f 100755 --- a/app/Http/Controllers/Api/UsersController.php +++ b/app/Http/Controllers/Api/UsersController.php @@ -2107,24 +2107,22 @@ class UsersController extends AbstractController { $user = User::auth(); // - global $_A; - if (!isset($_A["__annual__report_".$user->userid])) { - $year = '2023'; - $time = '2300-01-01 00:00:01'; - $prefix = \DB::getTablePrefix(); - $hireTimestamp = strtotime($user->created_at); - DB::statement("SET SQL_MODE=''"); + $year = '2023'; + $time = '2300-01-01 00:00:01'; + $prefix = \DB::getTablePrefix(); + $hireTimestamp = strtotime($user->created_at); + DB::statement("SET SQL_MODE=''"); - // 我的任务 - $taskDb = DB::table('project_tasks as t') - ->join('project_task_users as tu', 't.id', '=', 'tu.task_id') - ->where('tu.owner', 1) - ->whereYear('t.created_at', $year) - ->where('tu.userid', $user->userid); + // 我的任务 + $taskDb = DB::table('project_tasks as t') + ->join('project_task_users as tu', 't.id', '=', 'tu.task_id') + ->where('tu.owner', 1) + ->whereYear('t.created_at', $year) + ->where('tu.userid', $user->userid); - // 我的任务 - 时长(分钟) - $durationTaskDb = $taskDb->clone() - ->selectRaw(" + // 我的任务 - 时长(分钟) + $durationTaskDb = $taskDb->clone() + ->selectRaw(" {$prefix}t.id, {$prefix}t.flow_item_name, {$prefix}t.name as task_name, @@ -2136,14 +2134,14 @@ class UsersController extends AbstractController {$prefix}t.created_at, ifnull(TIMESTAMPDIFF(MINUTE, {$prefix}t.start_at, {$prefix}t.complete_at), 0) as duration ") - ->leftJoin('projects as p', 'p.id', '=', 't.project_id') - ->leftJoin('project_columns as c', 'c.id', '=', 't.column_id') - ->whereNotNull('t.start_at') - ->whereNotNull('t.complete_at'); + ->leftJoin('projects as p', 'p.id', '=', 't.project_id') + ->leftJoin('project_columns as c', 'c.id', '=', 't.column_id') + ->whereNotNull('t.start_at') + ->whereNotNull('t.complete_at'); - // 最多聊天用户 - $longestChat = DB::table('web_socket_dialogs as d') - ->selectRaw(" + // 最多聊天用户 + $longestChat = DB::table('web_socket_dialogs as d') + ->selectRaw(" {$prefix}d.id, {$prefix}d.name as dialog_name, {$prefix}d.type as dialog_type, @@ -2154,113 +2152,112 @@ class UsersController extends AbstractController {$prefix}u.nickname as user_nickname, ifnull({$prefix}d.avatar, {$prefix}u.userimg) as avatar ") - ->leftJoinSub(function ($query) use ($user, $year) { - $query->select('web_socket_dialog_msgs.dialog_id', DB::raw('count(*) as chat_num')) - ->from('web_socket_dialog_msgs') - ->where('web_socket_dialog_msgs.userid', $user->userid) - ->whereYear('web_socket_dialog_msgs.created_at', $year) - ->groupBy('web_socket_dialog_msgs.dialog_id'); - }, 'm', 'm.dialog_id', '=', 'd.id') - ->leftJoin('web_socket_dialog_users as du', function ($query) use ($user) { - $query->on('d.id', '=', 'du.dialog_id'); - $query->where('du.userid', '!=', $user->userid); - $query->where('d.type', 'user'); - }) - ->leftJoin('users as u', 'du.userid', '=', 'u.userid') - ->where('d.type', '!=', 'user') - ->orWhere('u.bot', 0) - ->orderByDesc('m.chat_num') - ->first(); - if (!empty($longestChat)) { - if ($longestChat->avatar) { - $longestChat->avatar = url($longestChat->avatar); - } else if ($longestChat->dialog_type == 'user') { - $longestChat->avatar = User::getAvatar($longestChat->userid, $longestChat->avatar, $longestChat->user_email, $longestChat->user_nickname); - } else { - $longestChat->avatar = match ($longestChat->dialog_group_type) { - 'department' => url("images/avatar/default_group_department.png"), - 'project' => url("images/avatar/default_group_project.png"), - 'task' => url("images/avatar/default_group_task.png"), - default => url("images/avatar/default_group_people.png"), - }; - } + ->leftJoinSub(function ($query) use ($user, $year) { + $query->select('web_socket_dialog_msgs.dialog_id', DB::raw('count(*) as chat_num')) + ->from('web_socket_dialog_msgs') + ->where('web_socket_dialog_msgs.userid', $user->userid) + ->whereYear('web_socket_dialog_msgs.created_at', $year) + ->groupBy('web_socket_dialog_msgs.dialog_id'); + }, 'm', 'm.dialog_id', '=', 'd.id') + ->leftJoin('web_socket_dialog_users as du', function ($query) use ($user) { + $query->on('d.id', '=', 'du.dialog_id'); + $query->where('du.userid', '!=', $user->userid); + $query->where('d.type', 'user'); + }) + ->leftJoin('users as u', 'du.userid', '=', 'u.userid') + ->where('d.type', '!=', 'user') + ->orWhere('u.bot', 0) + ->orderByDesc('m.chat_num') + ->first(); + if (!empty($longestChat)) { + if ($longestChat->avatar) { + $longestChat->avatar = url($longestChat->avatar); + } else if ($longestChat->dialog_type == 'user') { + $longestChat->avatar = User::getAvatar($longestChat->userid, $longestChat->avatar, $longestChat->user_email, $longestChat->user_nickname); + } else { + $longestChat->avatar = match ($longestChat->dialog_group_type) { + 'department' => url("images/avatar/default_group_department.png"), + 'project' => url("images/avatar/default_group_project.png"), + 'task' => url("images/avatar/default_group_task.png"), + default => url("images/avatar/default_group_people.png"), + }; } - - // 最晚在线时间 - $timezone = config('app.timezone'); - $latestOnline = UserCheckinRecord::whereUserid($user->userid) - ->whereYear(DB::raw('from_unixtime(report_time)'), $year) - ->orderByRaw("TIME_FORMAT(DATE_ADD(CONVERT_TZ(from_unixtime(report_time), 'UTC', '$timezone'), INTERVAL 18 HOUR), '%H%i%s') desc") - ->first(); - - // - $_A["__annual__report_".$user->userid] = [ - // 本人信息 - 'user' => [ - 'userid' => $user->userid, - 'email' => $user->email, - 'nickname' => $user->nickname, - 'avatar' => User::getAvatar($user->userid, $user->userimg, $user->email, $user->nickname) - ], - // 入职时间(年月日) - 'hire_date' => date("Y-m-d", $hireTimestamp), - // 在职时间(天为单位) - 'tenure_days' => floor((strtotime(date('Y-m-d')) - $hireTimestamp) / (24 * 60 * 60)), - // 最晚在线时间 - 'latest_online_time' => date("Y-m-d H:i:s", $latestOnline->report_time), - // 跟谁聊天最多(发消息的次数。可以是群、私聊、机器人除外) - 'longest_chat_user' => $longestChat, - // 跟所有ai机器人聊天的次数 - 'chat_al_num' => DB::table('web_socket_dialog_msgs as m') - ->join('web_socket_dialogs as d', 'd.id', '=', 'm.dialog_id') - ->join('web_socket_dialog_users as du', 'd.id', '=', 'du.dialog_id') - ->join('users as u', 'du.userid', '=', 'u.userid') - ->where('u.email', 'like', "%ai-%") - ->where('u.bot', 1) - ->where('m.userid', $user->userid) - ->whereYear('m.created_at', $year) - ->count(), - // 文件创建数量 - 'file_created_num' => File::whereCreatedId($user->userid)->whereYear('created_at', $year)->count(), - // 参与过的项目 - 'projects' => DB::table('projects as p') - ->select('p.id', 'p.name') - ->join('project_users as pu', 'p.id', '=', 'pu.project_id') - ->join('project_task_users as ptu', 'p.id', '=', 'ptu.project_id') - ->where(function($query) use ($user,$year) { - $query->where('pu.userid', $user->userid); - $query->whereYear('pu.created_at', $year); - }) - ->orWhere(function($query) use ($user,$year) { - $query->where('ptu.userid', $user->userid); - $query->whereYear('ptu.created_at', $year); - }) - ->groupBy('p.id') - ->take(100) - ->get(), - // 任务统计 - 'tasks' => [ - // 总数量 - 'total' => $taskDb->count(), - // 完成数量 - 'completed' => $taskDb->clone()->whereNotNUll('t.complete_at')->count(), - // 超时数量 - 'overtime' => $taskDb->clone()->whereRaw("ifnull({$prefix}t.complete_at,'$time') > ifnull({$prefix}t.end_at,'$time')")->count(), - // 做得最久的任务 - 'longest_task' => $durationTaskDb->clone()->orderByDesc('duration')->first(), - // 做得最快的任务 - 'fastest_task' => $durationTaskDb->clone()->orderBy('duration')->first(), - // 每个月完成多少个任务 - 'month_completed_task' => $taskDb->clone() - ->selectRaw("MONTH({$prefix}t.complete_at) AS month, COUNT({$prefix}t.id) AS num") - ->whereNotNUll('t.complete_at') - ->whereYear('t.complete_at', $year) - ->groupBy('month') - ->get() - ] - ]; } + + // 最晚在线时间 + $timezone = config('app.timezone'); + $latestOnline = UserCheckinRecord::whereUserid($user->userid) + ->whereYear(DB::raw('from_unixtime(report_time)'), $year) + ->orderByRaw("TIME_FORMAT(DATE_ADD(CONVERT_TZ(from_unixtime(report_time), 'UTC', '$timezone'), INTERVAL 18 HOUR), '%H%i%s') desc") + ->first(); + // - return Base::retSuccess('success', $_A["__annual__report_".$user->userid]); + $data = [ + // 本人信息 + 'user' => [ + 'userid' => $user->userid, + 'email' => $user->email, + 'nickname' => $user->nickname, + 'avatar' => User::getAvatar($user->userid, $user->userimg, $user->email, $user->nickname) + ], + // 入职时间(年月日) + 'hire_date' => date("Y-m-d", $hireTimestamp), + // 在职时间(天为单位) + 'tenure_days' => floor((strtotime(date('Y-m-d')) - $hireTimestamp) / (24 * 60 * 60)), + // 最晚在线时间 + 'latest_online_time' => date("Y-m-d H:i:s", $latestOnline->report_time), + // 跟谁聊天最多(发消息的次数。可以是群、私聊、机器人除外) + 'longest_chat_user' => $longestChat, + // 跟所有ai机器人聊天的次数 + 'chat_al_num' => DB::table('web_socket_dialog_msgs as m') + ->join('web_socket_dialogs as d', 'd.id', '=', 'm.dialog_id') + ->join('web_socket_dialog_users as du', 'd.id', '=', 'du.dialog_id') + ->join('users as u', 'du.userid', '=', 'u.userid') + ->where('u.email', 'like', "%ai-%") + ->where('u.bot', 1) + ->where('m.userid', $user->userid) + ->whereYear('m.created_at', $year) + ->count(), + // 文件创建数量 + 'file_created_num' => File::whereCreatedId($user->userid)->whereYear('created_at', $year)->count(), + // 参与过的项目 + 'projects' => DB::table('projects as p') + ->select('p.id', 'p.name') + ->join('project_users as pu', 'p.id', '=', 'pu.project_id') + ->join('project_task_users as ptu', 'p.id', '=', 'ptu.project_id') + ->where(function($query) use ($user,$year) { + $query->where('pu.userid', $user->userid); + $query->whereYear('pu.created_at', $year); + }) + ->orWhere(function($query) use ($user,$year) { + $query->where('ptu.userid', $user->userid); + $query->whereYear('ptu.created_at', $year); + }) + ->groupBy('p.id') + ->take(100) + ->get(), + // 任务统计 + 'tasks' => [ + // 总数量 + 'total' => $taskDb->count(), + // 完成数量 + 'completed' => $taskDb->clone()->whereNotNUll('t.complete_at')->count(), + // 超时数量 + 'overtime' => $taskDb->clone()->whereRaw("ifnull({$prefix}t.complete_at,'$time') > ifnull({$prefix}t.end_at,'$time')")->count(), + // 做得最久的任务 + 'longest_task' => $durationTaskDb->clone()->orderByDesc('duration')->first(), + // 做得最快的任务 + 'fastest_task' => $durationTaskDb->clone()->orderBy('duration')->first(), + // 每个月完成多少个任务 + 'month_completed_task' => $taskDb->clone() + ->selectRaw("MONTH({$prefix}t.complete_at) AS month, COUNT({$prefix}t.id) AS num") + ->whereNotNUll('t.complete_at') + ->whereYear('t.complete_at', $year) + ->groupBy('month') + ->get() + ] + ]; + // + return Base::retSuccess('success', $data); } } diff --git a/app/Http/Middleware/WebApi.php b/app/Http/Middleware/WebApi.php index fcb4b751a..fc100a4f3 100644 --- a/app/Http/Middleware/WebApi.php +++ b/app/Http/Middleware/WebApi.php @@ -5,6 +5,7 @@ namespace App\Http\Middleware; @error_reporting(E_ALL & ~E_NOTICE & ~E_WARNING); use App\Module\Doo; +use App\Services\RequestContext; use Closure; class WebApi @@ -18,11 +19,14 @@ class WebApi */ public function handle($request, Closure $next) { - global $_A; - $_A = []; + // 为每个请求生成唯一ID + $request->requestId = RequestContext::generateRequestId(); + RequestContext::set('start_time', microtime(true)); + // 加载Doo类 Doo::load(); + // 解密请求内容 $encrypt = Doo::pgpParseStr($request->header('encrypt')); if ($request->isMethod('post')) { $version = $request->header('version'); @@ -47,6 +51,7 @@ class WebApi $request->setTrustedProxies([$request->getClientIp()], $request::HEADER_X_FORWARDED_PROTO); } + // 执行下一个中间件 $response = $next($request); // 加密返回内容 @@ -57,6 +62,16 @@ class WebApi } } + // 返回响应 return $response; } + + /** + * @return void + */ + public function terminate() + { + // 请求结束后清理上下文 + RequestContext::clear(); + } } diff --git a/app/Models/User.php b/app/Models/User.php index a1cff461e..b0f41d6f2 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -6,6 +6,7 @@ namespace App\Models; use App\Exceptions\ApiException; use App\Module\Base; use App\Module\Doo; +use App\Services\RequestContext; use Cache; use Carbon\Carbon; use Request; @@ -435,9 +436,8 @@ class User extends AbstractModel */ private static function authInfo() { - global $_A; - if (isset($_A["__static_auth"])) { - return $_A["__static_auth"]; + if (RequestContext::has('auth')) { + return RequestContext::get('auth'); } if (Doo::userId() > 0 && !Doo::userExpired() @@ -459,9 +459,9 @@ class User extends AbstractModel $user->updateInstance($upArray); $user->save(); } - return $_A["__static_auth"] = $user; + return RequestContext::save('auth', $user); } - return $_A["__static_auth"] = false; + return RequestContext::save('auth', false); } /** @@ -497,20 +497,19 @@ class User extends AbstractModel */ public static function userid2basic($userid, $addField = []) { - global $_A; if (empty($userid)) { return null; } $userid = intval($userid); - if (isset($_A["__static_userid2basic_" . $userid])) { - return $_A["__static_userid2basic_" . $userid]; + if (RequestContext::has("userid2basic_" . $userid)) { + return RequestContext::get("userid2basic_" . $userid); } $userInfo = self::whereUserid($userid)->select(array_merge(User::$basicField, $addField))->first(); if ($userInfo) { $userInfo->online = $userInfo->getOnlineStatus(); $userInfo->department_name = $userInfo->getDepartmentName(); } - return $_A["__static_userid2basic_" . $userid] = ($userInfo ?: []); + return RequestContext::save("userid2basic_" . $userid, $userInfo ?: []); } diff --git a/app/Models/UserBot.php b/app/Models/UserBot.php index e5cbdca06..a83dcea72 100644 --- a/app/Models/UserBot.php +++ b/app/Models/UserBot.php @@ -284,7 +284,7 @@ class UserBot extends AbstractModel ]; } } elseif (preg_match('/^(manual|locat|face|checkin)-(\d+)$/i', $mac, $match)) { - $type = strtolower(str_replace('checkin', 'face', $match[1])); + $type = str_replace('checkin', 'face', strtolower($match[1])); $mac = intval($match[2]); $remark = match ($type) { 'manual' => $setting['manual_remark'] ?: 'Manual', diff --git a/app/Module/Base.php b/app/Module/Base.php index 4229fccb3..132974871 100755 --- a/app/Module/Base.php +++ b/app/Module/Base.php @@ -5,6 +5,7 @@ namespace App\Module; use App\Exceptions\ApiException; use App\Models\Setting; use App\Models\Tmp; +use App\Services\RequestContext; use Cache; use Carbon\Carbon; use League\CommonMark\CommonMarkConverter; @@ -125,11 +126,10 @@ class Base */ public static function getClientVersion() { - global $_A; - if (!isset($_A["__static_client_version"])) { - $_A["__static_client_version"] = self::headerOrInput('version') ?: '0.0.1'; + if (RequestContext::has('client_version')) { + return RequestContext::get('client_version'); } - return $_A["__static_client_version"]; + return RequestContext::save('client_version', self::headerOrInput('version') ?: '0.0.1'); } /** @@ -757,7 +757,6 @@ class Base */ public static function fillUrl($str = '') { - global $_A; if (is_array($str)) { foreach ($str as $key => $item) { $str[$key] = Base::fillUrl($item); @@ -776,7 +775,7 @@ class Base ) { return $str; } else { - if ($_A['__fill_url_remote_url'] === true) { + if (RequestContext::has('fill_url_remote_url')) { return "{{RemoteURL}}" . $str; } try { @@ -1298,12 +1297,11 @@ class Base */ public static function setting($setname, $array = false, $isUpdate = false) { - global $_A; if (empty($setname)) { return []; } - if ($array === false && isset($_A["__static_setting_" . $setname])) { - return $_A["__static_setting_" . $setname]; + if ($array === false && RequestContext::has('setting_' . $setname)) { + return RequestContext::get('setting_' . $setname); } $setting = []; $row = Setting::whereName($setname)->first(); @@ -1322,8 +1320,7 @@ class Base $row->updateInstance(['setting' => $setting]); $row->save(); } - $_A["__static_setting_" . $setname] = $setting; - return $setting; + return RequestContext::save('setting_' . $setname, $setting); } /** @@ -1739,16 +1736,11 @@ class Base /** * 获取时间戳 - * @param bool $refresh * @return int */ - public static function time($refresh = false) + public static function time() { - global $_A; - if (!isset($_A["__static_time"]) || $refresh === true) { - $_A["__static_time"] = time(); - } - return $_A["__static_time"]; + return intval(RequestContext::get("start_time", time())); } /** @@ -1833,29 +1825,28 @@ class Base */ public static function getIp() { - global $_A; - if (!isset($_A["__static_ip"])) { - if (getenv('HTTP_CLIENT_IP') and strcasecmp(getenv('HTTP_CLIENT_IP'), 'unknown')) { - $onlineip = getenv('HTTP_CLIENT_IP'); - } elseif (isset($_SERVER['HTTP_CLIENT_IP']) and $_SERVER['HTTP_CLIENT_IP'] and strcasecmp($_SERVER['HTTP_CLIENT_IP'], 'unknown')) { - $onlineip = $_SERVER['HTTP_CLIENT_IP']; - } elseif (getenv('HTTP_X_FORWARDED_FOR') and strcasecmp(getenv('HTTP_X_FORWARDED_FOR'), 'unknown')) { - $onlineip = getenv('HTTP_X_FORWARDED_FOR'); - } elseif (isset($_SERVER['HTTP_X_FORWARDED_FOR']) and $_SERVER['HTTP_X_FORWARDED_FOR'] and strcasecmp($_SERVER['HTTP_X_FORWARDED_FOR'], 'unknown')) { - $onlineip = $_SERVER['HTTP_X_FORWARDED_FOR']; - } elseif (getenv('REMOTE_ADDR') and strcasecmp(getenv('REMOTE_ADDR'), 'unknown')) { - $onlineip = getenv('REMOTE_ADDR'); - } elseif (isset($_SERVER['REMOTE_ADDR']) and $_SERVER['REMOTE_ADDR'] and strcasecmp($_SERVER['REMOTE_ADDR'], 'unknown')) { - $onlineip = $_SERVER['REMOTE_ADDR']; - } elseif (Request::header('X-Real-IP')) { - $onlineip = Request::header('X-Real-IP'); - } else { - $onlineip = '0,0,0,0'; - } - preg_match("/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/", $onlineip, $match); - $_A["__static_ip"] = $match ? ($match[0] ?: 'unknown') : ''; + if (RequestContext::has("static_ip")) { + return RequestContext::get("static_ip"); } - return $_A["__static_ip"]; + if (getenv('HTTP_CLIENT_IP') and strcasecmp(getenv('HTTP_CLIENT_IP'), 'unknown')) { + $onlineip = getenv('HTTP_CLIENT_IP'); + } elseif (isset($_SERVER['HTTP_CLIENT_IP']) and $_SERVER['HTTP_CLIENT_IP'] and strcasecmp($_SERVER['HTTP_CLIENT_IP'], 'unknown')) { + $onlineip = $_SERVER['HTTP_CLIENT_IP']; + } elseif (getenv('HTTP_X_FORWARDED_FOR') and strcasecmp(getenv('HTTP_X_FORWARDED_FOR'), 'unknown')) { + $onlineip = getenv('HTTP_X_FORWARDED_FOR'); + } elseif (isset($_SERVER['HTTP_X_FORWARDED_FOR']) and $_SERVER['HTTP_X_FORWARDED_FOR'] and strcasecmp($_SERVER['HTTP_X_FORWARDED_FOR'], 'unknown')) { + $onlineip = $_SERVER['HTTP_X_FORWARDED_FOR']; + } elseif (getenv('REMOTE_ADDR') and strcasecmp(getenv('REMOTE_ADDR'), 'unknown')) { + $onlineip = getenv('REMOTE_ADDR'); + } elseif (isset($_SERVER['REMOTE_ADDR']) and $_SERVER['REMOTE_ADDR'] and strcasecmp($_SERVER['REMOTE_ADDR'], 'unknown')) { + $onlineip = $_SERVER['REMOTE_ADDR']; + } elseif (Request::header('X-Real-IP')) { + $onlineip = Request::header('X-Real-IP'); + } else { + $onlineip = '0,0,0,0'; + } + preg_match("/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/", $onlineip, $match); + return RequestContext::save("static_ip", $match ? ($match[0] ?: 'unknown') : ''); } /** diff --git a/app/Module/Table/AbstractData.php b/app/Module/Table/AbstractData.php new file mode 100644 index 000000000..956fa490a --- /dev/null +++ b/app/Module/Table/AbstractData.php @@ -0,0 +1,86 @@ +getShortName(); + return lcfirst($className) . 'Table'; + } + + private function __clone() {} + private function __wakeup() {} + + protected function __construct() + { + $this->table = app('swoole')->{$this->getTableName()}; + } + + public function getTable() + { + return $this->table; + } + + public static function instance() + { + if (static::$instance === null) { + static::$instance = new static(); + } + return static::$instance; + } + + public static function set($key, $value) + { + return self::instance()->table->set($key, ['value' => $value]); + } + + public static function get($key, $default = null) + { + $data = self::instance()->table->get($key); + return $data ? $data['value'] : $default; + } + + public static function del($key) + { + return self::instance()->table->del($key); + } + + public static function exist($key) + { + return self::instance()->table->exist($key); + } + + public static function setMultiple(array $items) + { + foreach ($items as $key => $value) { + self::set($key, $value); + } + } + + public static function clear() + { + foreach (self::instance()->table as $key => $row) { + self::del($key); + } + } + + public static function getAll() + { + $result = []; + foreach (self::instance()->table as $key => $row) { + $result[$key] = $row['value']; + } + return $result; + } +} diff --git a/app/Module/Table/GlobalData.php b/app/Module/Table/GlobalData.php new file mode 100644 index 000000000..1c368cb75 --- /dev/null +++ b/app/Module/Table/GlobalData.php @@ -0,0 +1,7 @@ +> */ + private static array $context = []; + + private const REQUEST_ID_PREFIX = 'req_'; + + /** + * 生成请求唯一ID + */ + public static function generateRequestId(): string + { + return self::REQUEST_ID_PREFIX . uniqid() . mt_rand(10000, 99999); + } + + /** + * 获取当前请求ID + */ + private static function getCurrentRequestId(): ?string + { + /** @var Request $request */ + $request = request(); + return $request?->requestId; + } + + /** + * 设置请求上下文 + * + * @param string $key + * @param mixed $value + * @param string|null $requestId + * @return void + */ + public static function set(string $key, mixed $value, ?string $requestId = null): void + { + $requestId = $requestId ?? self::getCurrentRequestId(); + if ($requestId === null) { + return; + } + + self::$context[$requestId] ??= []; + self::$context[$requestId][$key] = $value; + } + + // 与 set 方法的区别是,save 方法会返回传入的 value 值 + public static function save(string $key, mixed $value, ?string $requestId = null): mixed + { + self::set($key, $value, $requestId); + return $value; + } + + /** + * 获取请求上下文 + * + * @param string $key + * @param mixed $default + * @param string|null $requestId + * @return mixed + */ + public static function get(string $key, mixed $default = null, ?string $requestId = null): mixed + { + $requestId = $requestId ?? self::getCurrentRequestId(); + if ($requestId === null) { + return $default; + } + + return self::$context[$requestId][$key] ?? $default; + } + + /** + * 判断请求上下文是否存在 + * + * @param string $key + * @param string|null $requestId + * @return bool + */ + public static function has(string $key, ?string $requestId = null): bool + { + $requestId = $requestId ?? self::getCurrentRequestId(); + if ($requestId === null) { + return false; + } + + return isset(self::$context[$requestId][$key]); + } + + /** + * 清理请求上下文 + * + * @param string|null $requestId + * @return void + */ + public static function clear(?string $requestId = null): void + { + $requestId = $requestId ?? self::getCurrentRequestId(); + if ($requestId === null) { + return; + } + + unset(self::$context[$requestId]); + } + + /** + * 获取当前请求的所有上下文数据 + * + * @param string|null $requestId + * @return array + */ + public static function getAll(?string $requestId = null): array + { + $requestId = $requestId ?? self::getCurrentRequestId(); + if ($requestId === null) { + return []; + } + + return self::$context[$requestId] ?? []; + } + + /** + * 批量设置上下文数据 + * + * @param array $data + * @param string|null $requestId + * @return void + */ + public static function setMultiple(array $data, ?string $requestId = null): void + { + $requestId = $requestId ?? self::getCurrentRequestId(); + if ($requestId === null) { + return; + } + + self::$context[$requestId] ??= []; + self::$context[$requestId] = array_merge(self::$context[$requestId], $data); + } +} diff --git a/app/Tasks/WebSocketDialogMsgTask.php b/app/Tasks/WebSocketDialogMsgTask.php index 29b217ff0..910a360f9 100644 --- a/app/Tasks/WebSocketDialogMsgTask.php +++ b/app/Tasks/WebSocketDialogMsgTask.php @@ -10,6 +10,7 @@ use App\Models\WebSocketDialogMsg; use App\Models\WebSocketDialogMsgRead; use App\Module\Base; use App\Module\Doo; +use App\Services\RequestContext; use Carbon\Carbon; use Hhxsv5\LaravelS\Swoole\Task\Task; use Request; @@ -78,11 +79,7 @@ class WebSocketDialogMsgTask extends AbstractTask public function start() { - global $_A; - $_A = [ - '__fill_url_remote_url' => true, - ]; - + RequestContext::set('fill_url_remote_url', true); // $msg = WebSocketDialogMsg::find($this->id); if (empty($msg)) { diff --git a/config/laravels.php b/config/laravels.php index bad61e7a8..51602f2f6 100644 --- a/config/laravels.php +++ b/config/laravels.php @@ -134,7 +134,6 @@ return [ */ 'event_handlers' => [ - 'ServerStart' => \App\Events\ServerStartEvent::class, 'WorkerStart' => \App\Events\WorkerStartEvent::class, ], @@ -222,7 +221,38 @@ return [ | */ - 'swoole_tables' => [], + 'swoole_tables' => [ + 'initFlag' => [ + 'size' => 1, + 'column' => [ + [ + 'name' => 'value', + 'type' => \Swoole\Table::TYPE_INT, + 'size' => 8 + ], + ], + ], + 'globalData' => [ + 'size' => 1024, + 'column' => [ + [ + 'name' => 'value', + 'type' => \Swoole\Table::TYPE_STRING, + 'size' => 1024 + ], + ], + ], + 'onlineData' => [ + 'size' => 10240, + 'column' => [ + [ + 'name' => 'value', + 'type' => \Swoole\Table::TYPE_INT, + 'size' => 8 + ], + ], + ], + ], /* |--------------------------------------------------------------------------